2016-06-30 1 views
0

今日私は何か変わった(私にとって)何かを見つけました。私のViewModelのプロパティを使ってDataGridを更新したい場合、Bindingは通知されません。特別なのは、私が思うに、バインディングは、私が変更するプロパティではなく、別のオブジェクト(コレクションの一部)にバインドされていると思います。DataGridの背景をViewModelのバインディングから更新する

サンプルコードを用意しました。しかし、少し(デッパー)説明。

もちろんこれは単なるサンプルですが、ここでは2つのパブリックプロパティ(ItemsとCurrentItem)を持つViewModelがあります。 ItemsはObservableCollectionで、DataGridのItemsSourceとして機能します。 CurrentItemは、グリッドの背景色を設定するコンバータのインジケータとして機能するStringです。

2つのインスタンスを追加します。コレクションに文字列を追加し、プログラムを開始した後、動作が期待通りに行われます。最初の行は緑で、2番目の行は白です(コンバーターとプロパティで設定)。

しかし、プログラムがロードされた後でCurrentItemの値を変更すると、データグリッドで色が更新されません。

コンバータの先頭にブレークポイントを作成すると、(読み込みプロセス後に)コンバーターが再び実行されるのを見ることができるので、バインディングの問題でなければなりません。私は問題が私のコレクションのアイテムの一部ではない私の財産だと思う。 OnPropertyChangeメソッドは、RowStyleの更新を適切にトリガーしないようです。

実生活では、コレクションのモデルクラスは文字列ではなく、モデルクラスはINotifyPropertyChangeを実装しています(ただし、これはモデル内の何も更新していないため問題ありません)。

動的インジケータ(この例に似ています)に基づいて、より多くの行をハイライト表示するには、この種の動作が必要です。誰も私がモデルの中にある種のPropertyを実装し、ViewModelからメソッドを使ってプロパティを更新するより良い方法を知っていないと思っています。

のViewModel:長いPOSのためのとても残念

public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    public static MainWindowViewModel instance = null; 

    private string _CurrentItem; 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string Property) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(Property)); 
     } 
    } 

    public string CurrentItem 
    { 
     get 
     { 
      return _CurrentItem; 
     } 
     set 
     { 
      if (value != _CurrentItem) 
      { 
       _CurrentItem = value; 
       OnPropertyChanged("CurrentItem"); 
       OnPropertyChanged("Items"); 
      } 
     } 
    } 
    public ObservableCollection<String> Items { get; set; } 

    public MainWindowViewModel() 
    { 
     instance = this; 
     Items = new ObservableCollection<string>(); 

     CurrentItem = "First"; 

     Items.Add("First"); 
     Items.Add("Second"); 
     Items.Add("First"); 

    } 

ビューXAML

<Window.DataContext> 
    <local:MainWindowViewModel /> 
</Window.DataContext> 
<Window.Resources> 
    <local:StringToColorConverter x:Key="StringToColorConverter" /> 
</Window.Resources> 
<DockPanel Margin="30"> 
    <Button DockPanel.Dock="bottom" Content="From First to Second" Click="Button_Click" /> 
    <DataGrid IsReadOnly="True" ItemsSource="{Binding Items}" ColumnWidth="*" AutoGenerateColumns="False"> 
     <DataGrid.RowStyle> 
      <Style TargetType="DataGridRow"> 
       <Setter Property="Background" 
         Value="{Binding Converter={StaticResource StringToColorConverter}}" /> 
      </Style> 
     </DataGrid.RowStyle> 
     <DataGrid.Columns> 
      <DataGridTextColumn Header="Text" Binding="{Binding}" /> 
     </DataGrid.Columns> 
    </DataGrid> 
</DockPanel> 

コンバータ

public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
{ 
    var item = value as string; 

    if (item == MainWindowViewModel.instance?.CurrentItem) 
     return "Green"; 
    return "White"; 
} 

あなたが私の問題を理解することができ、もちろん私を助けてくれることを願っています:)

+2

を使用してのCurrentItemを含むことができます。 XAMLはそれが存在していると推測し、どのように変化するかを気にする必要はありませんか? –

+0

私はEdに同意し、Edのコメントが来ている間私は自分の投稿を編集していました。 @Badoは、CurrentItemが現在Datagridで選択されている行である場合に可能な別の解決策です。 Is CurrentItem currenlty選択された行ですか? –

+0

はい私はそれのような何かを考えました。したがって、ObservableCollectionに項目を変更せずにBindingsを更新するように強制する方法はありません。あなたが私の例で見ることができるように、私はINotifyPropertyChangedでそれを試しました。 CurrentItemという名前はちょっと混乱しているかもしれません。現在選択されている項目ではなく、どの行が緑色で、どの行が白色であるべきかをコンバータに知らせるためのベースとなる指標です。このインジケータを通して、複数の行が緑色にマークされることもあります(ただし、私の例ではありません:))。 – Bado

答えて

2

あなたは `CurrentItem`が何にバインドされていない、付属XAMLでIMultiValueConverter

<DataGrid.RowStyle> 
    <Style TargetType="DataGridRow"> 
     <Setter Property="Background"> 
      <Setter.Value> 
       <MultiBinding Converter="{StaticResource MultiStringToColorConverter}"> 
        <Binding /> 
        <Binding Path="DataContext.CurrentItem" 
          RelativeSource="{RelativeSource FindAncestor, 
               AncestorType={x:Type Window}}"/> 
       </MultiBinding> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</DataGrid.RowStyle> 

コンバータ

public class MultiStringToColorConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, 
        System.Globalization.CultureInfo culture) 
    { 
     var item = values[0] as string; 
     var current = values[1] as string; 

     if (item == current) 
      return new SolidColorBrush(Colors.Green); 
     return new SolidColorBrush(Colors.White); 
    } 

    public object[] ConvertBack(object values, Type[] targetType, object parameter, 
        System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 
+0

これは私の解決策でした!大いに感謝する。 – Bado

2

すべてが正常です!

これは仕様です。 背景は、DataGridのn番目のオブジェクトにバインドされています。 これはCurrentItemにバインドされていないため、バインディングがn番目の行の背景を更新する理由はありません。

あなたはのObservableCollectionを持っているので、あなたがMYITEMクラス でIsSelectedプロパティを置くことができそして、あなたはMYITEMIsSelected財産上のPropertyChangedイベントを発生させる必要があります。もちろん

<DataGrid.RowStyle> 
    <Style TargetType="DataGridRow"> 
    <Setter Property="Background" 
        Value="{Binding Path=IsSelected, 
            Converter={StaticResource BooleanToColorConverter}}" /> 
    </Style> 
</DataGrid.RowStyle> 

がBooleanToColorConvertにStringToColorConverterを変更些細wouldbe:INotifyPropertyChanged

最終を実装し、もちろんMYITEM

、あなたはバインディング変更する必要があります。

よろしく

+0

彼はあまりにもトリガーを行うことができます。 –

関連する問題