2016-11-23 12 views
0

私は、文字列のリストを改行で1つの文字列に変換することによってテキストのブロックを作成するだけでした。このバインディングは機能しました。それが想定されていたときに更新されましたが、将来のある時点でハイパーリンクにする必要があるため、ItemsControlにテキストのリストを移動しようとしています。問題:PropertyChangeEventが発生したときにItemsControlは変更されません。私は人々がそれを見るために頼むことを知っているという理由だけでItemsControl ItemSourceバインディングが更新されない

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> 

のViewModel

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

私は、Listの代わりにObservableCollectionを使用することでコードを動作させることができました。 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

ありがとう、このソリューションはうまくいきました。将来Observable Collectionを好む – Sonic1015

-1

コンストラクタの前にget setメソッドでOnPropertyChanged()メソッドを設定しましたが、これはうまくいきました。

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

.xamlに{Binding TheString}を使用してください。

希望すると便利です。

+0

私は "ErrorDTOOnPropertyChanged"メソッドにあるOnPropertyChangedを呼び出します。私はあなたの提案を試みましたが、変更はありません:( – 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 
    } 

うまくいけば。

関連する問題