2016-11-23 89 views
0

我以前只是通过将一串字符串转换为一个带有换行符的字符串来创建一段文本。这个绑定工作;当它应该和所有,但我试图将文本列表移动到一个ItemsControl,因为他们将需要在未来的某个点超链接。问题:当PropertyChangeEvent被触发时,ItemsControl不会改变。相关代码如下:ItemsControlSourceSource Binding not updating

的XAML

<local:BaseUserControl x:Class="BAC.Windows.UI.Views.ErrorsView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:BAC.Windows.UI.Views" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 

      ... 

      <ItemsControl ItemsSource="{Binding Path=ErrorMessages}"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <TextBlock Text="{Binding}"></TextBlock> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
      </ItemsControl> 

      <!--<TextBlock VerticalAlignment="Center" Visibility="{Binding ErrorMessages, Converter={StaticResource VisibleWhenNotEmptyConverter}}" Text="{Binding ErrorMessages, Converter={StaticResource ErrorMessagesToTextConverter}}"> 

      (What I used to use) 

      </TextBlock>--> 


... 

</local:BaseUserControl> 

视图模型

using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Linq; 
using ASI.Core.Core; 
using ASI.Core.DTO; 
using ASI.Core.Extensions; 
using ASI.Core.Mappers; 
using BAC.Core.Resources; 
using BAC.Core.Services; 
using BAC.Core.ViewModels.Views; 

namespace BAC.Core.ViewModels 
{ 
    public interface IErrorsViewModel : IViewModel<IErrorsView> 
    { 
    } 

    public class ErrorsViewModel : BaseViewModel<IErrorsView>, IErrorsViewModel 
    { 
     ... 

     private readonly ErrorDTO _errorDTO; 
     private readonly ErrorDTO _warningDTO; 

     public ErrorsViewModel(...) : base(view) 
     { 
      ... 

      //Just added this string to know that it's at least binding. This Message displays, and never changes. 
      ErrorMessages = new List<string>() {"Simple Message"}; 

      //Tells the View to bind dataContext to Viewmodel 
      Edit(); 
     } 

     private void errorDTOOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) 
     { 
      ErrorDTO dto; 
      if (!string.Equals(propertyChangedEventArgs.PropertyName, nameof(dto.HasError))) return; 

      ErrorMessages.Clear(); 
      _errorDTO.ErrorMessages.Each(x => ErrorMessages.Add(Constants.Captions.Errors + ": " + x)); 
      _warningDTO.ErrorMessages.Each(x => ErrorMessages.Add(Constants.Captions.Warnings + ": " + x)); 

      OnPropertyChanged(() => ErrorMessages); 
      OnPropertyChanged(() => HasError); 
      OnPropertyChanged(() => HasWarning); 
     } 

     ... 

     public bool HasError => _errorDTO.HasError; 

     public bool HasWarning => _warningDTO.HasError; 

     public IList<string> ErrorMessages { get; set; } 

     ... 
} 

而只是因为我知道有人会问,看它...

public class BaseNotifyPropertyChanged : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 
     [NotifyPropertyChangedInvocator] 
     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
     { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
     } 

     public void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression) 
     { 
     var body = propertyExpression.Body as MemberExpression; 
     if (body != null) 
      OnPropertyChanged(body.Member.Name); 
     } 

     protected void OnEvent(Action action) 
     { 
      try 
      { 
       action(); 
      } 
      catch 
      { } 
     } 
    } 

我我肯定这简直是一件愚蠢的事情,但我看起来越难,我就越容易被某种简单的东西吓倒。为什么该绑定对于除ItemSource之外的其他所有控件都适用?这有什么特别之处?

回答

1

因此,我能够通过使用ObservableCollection而不是List来让您的代码工作。当ObservableCollection集合发生更改时,会自动生成一个列表更改通知。以下是我的示例代码。我使用计时器每秒更新错误列表。

<Window x:Class="TestEer.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:TestEer" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}}"> 
<Grid> 
    <ItemsControl ItemsSource="{Binding Path=ErrorMessages}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding}" /> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

using System.Collections.ObjectModel; 
using System.Timers; 
using System.Windows; 
using System.Windows.Data; 

namespace TestEer 
{ 
/// <summary> 
/// Interaction logic for MainWindow.xaml 
/// </summary> 
public partial class MainWindow : Window 
{ 
    private Timer _timer; 
    private readonly object _sync = new object(); 
    public MainWindow() 
    { 
     InitializeComponent(); 
     BindingOperations.EnableCollectionSynchronization(ErrorMessages, _sync); 
     _timer = new Timer 
     { 
      AutoReset = true, 
      Interval = 1000 
     }; 

     _timer.Elapsed += _timer_Elapsed; 
     _timer.Enabled = true; 
     _timer.Start(); 
    } 

    private void _timer_Elapsed(object sender, ElapsedEventArgs e) 
    { 
     ErrorMessages.Add($"Error @ {e.SignalTime}"); 
    } 

    public ObservableCollection<string> ErrorMessages { get; } = new ObservableCollection<string>(); 
} 
} 
+0

非常感谢你,这个解决方案工作。我会记住,ItemSource控件更喜欢未来的Observable Collection。 – Sonic1015

-1

我们在构造函数之前的get set方法中设置了OnPropertyChanged()方法,这看起来很有效!

private bool _theString; 
public bool TheString 
{ 
    get { return _theString; } 
    set { _theString = value; OnPropertyChanged(); } 
} 

使用{Binding TheString}在你的.xaml。

希望这会有所帮助!

+0

我确实调用了OnPropertyChanged,它在“errorDTOOnPropertyChanged”方法中。我确实尝试了你的建议,但没有改变:(。 – Sonic1015

+0

该死的解决了我们,不知道什么问题可能是:( – NinjaFocks

0

我还将添加anotehr解释(虽然我知道这是旧的)。

这将不会更新属性的原因是List对象实际上并没有更改,所以ListView不会更新列表。要做到这一点,而不使用“的ObservableCollection”的唯一方法是在每个属性改变创建一个全新的列表,像这样:

private void errorDTOOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs) 
    { 
     if (!string.Equals(propertyChangedEventArgs.PropertyName, nameof(dto.HasError))) return; 
      OnPropertyChanged(() => ErrorMessages); 
    } 

    public List<string> ErrorMessages => getErrorMessages(); 

    private List<string> getErrorMessages() { 
     //create list in a manner of your choosing 
    } 

希望帮助人,当他们碰上这一点。