2017-06-23 21 views
-1

私は、プロジェクトを明示するためにWPFプロジェクトを作成しました。NotifyOfPropertyChangeがDataGridでトリガーされていません

免責事項:私はPropertyChangedBaseBindableCollectionを使用する場合にのみCaliburn.Microを使用しています。このプロジェクトの他のすべては、定型的なWPFのものです。

右のように、クラスはDataItemです。 Qty呼ば

  • int、そして
  • QtyのダブルですSumと呼ばれる計算されたプロパティ、:それはちょうど2つのプロパティを持っています。

これだけです。わかりやすくするために、コードは次のとおりです。

public class DataLine : PropertyChangedBase 
{ 
    private int qty; 

    public int Qty 
    { 
     get 
     { 
      return qty; 
     } 

     set 
     { 
      if (value == qty) 
      { 
       return; 
      } 

      qty = value; 
      NotifyOfPropertyChange(); 
      NotifyOfPropertyChange(() => Sum); 
     } 
    } 

    public int Sum => qty * 2; 

    public DataLine(int a) 
    { 
     Qty = a;    
    } 
} 

今、ViewModelです。それはDataLinesのすべてSumを追加し、

  • のICommandますDataLineBindableCollectionObservableCollectionのカリバーンの味である)、
  • int

    • を持っています。

    のICommandはBindableCollectionintのトリガーNotifyPropertyChangedが、何もしません。 Viewのために、今すぐ

    class ViewModel: PropertyChangedBase 
    { 
        public ViewModel() 
        { 
         Data = new BindableCollection<DataLine> 
         { 
          new DataLine(1), 
          new DataLine(2), 
          new DataLine(4), 
          new DataLine(6) 
         }; 
    
         RefreshCommand = new RefreshCommand(this); 
        } 
    
        private BindableCollection<DataLine> _data; 
    
        public BindableCollection<DataLine> Data 
        { 
         get 
         { 
          return _data; 
         } 
    
         set 
         { 
          if (value == _data) 
          { 
           return; 
          } 
    
          _data = value; 
          NotifyOfPropertyChange(); 
          NotifyOfPropertyChange(() => Amount); 
         } 
        } 
    
        public ICommand RefreshCommand { get; private set; } 
    
        public void RefreshAction() 
        { 
         NotifyOfPropertyChange(() => Data); 
         NotifyOfPropertyChange(() => Amount); 
        } 
    
        public int? Amount => Data?.Sum(c => c.Sum); 
    
    } 
    

    は、ここでは、コードです それは非常に簡単です。

    • BindableCollectionにバインドされたDataGridがあります。
    • Buttonがあり、ICommandにバインドされています。
    • 「テキストボックス, bound to金額」があります。

    ここViewのボディです:

    <DockPanel>   
        <TextBox DockPanel.Dock="Bottom" Text="{Binding Amount, TargetNullValue='', Mode=OneWay}"/> 
        <Button DockPanel.Dock="Bottom" Command="{Binding RefreshCommand}" Content="Refresh"/> 
        <DataGrid ItemsSource="{Binding Data, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="True"/> 
    </DockPanel> 
    

    私はそれを実行すると、私はこのような何かを得る:

    Initial Window

    今トリッキーな部分が来る - 私はちょうど編集してみましょう行の1つ。

    Edited

    は、明瞭にするために、私は私のカーソルがDataGridを編集した後だった場所を示すために矢印が追加されました。最初の行のSumがどのように更新されているかを確認しますが、画面下部のAmountは同じままです。私はRefreshをクリックしたときに

    は今、これが起こる:

    The Updated View

    Amountが正しく更新されます。

    最終的に私の質問につながります。DataGridの何が問題なのですか?行が編集されたときにDataGridがそのセッターをトリガーしないのはなぜですか?そして、どのようにトリガーされていることを確認することができますか?

  • +1

    BindableCollection内のオブジェクトのプロパティを変更すると、コレクションプロパティ自体が魔法のように変更されることが予想されますか?コレクションエレメントを編集するだけで、データセッターは呼び出されません。だから、 "DataGridの何が問題なの?"何も、あなたの間違った期待です。 – Clemens

    +0

    子オブジェクトのいずれかが編集されたときにコレクション自体に 'NotifyOfPropertyChange()'を呼び出す方法はありますか? –

    +0

    もちろん、DataLineは何らかの形で親ビューモデルにアクセスでき、 'NotifyOfPropertyChange()=> Amount)'メソッドを呼び出すことができます。 – Clemens

    答えて

    1

    私は、データグリッドを見つけ、メタ/集計データを更新することが時々あります。 現在、Clemensはあなたのニーズに合わせてBindableCollectionを簡単に変更できるかどうか分かりません。

    しかし、DataLineViewModelの間に緊密なカップルを作成しないでください。あなたはいつも抽象化やジェネリックを使っていつでも気になることができます。しかし、私はあなたのコードの簡単な編集を作成して、私の意味を示しました。

    実質的には、ViewModelがアクションをオブジェクトに渡すことができるようなメカニズムを作成します。私がこれを実装していたなら、おそらくInterfaceまたはGenericのいくつかのフォームを実装して、それぞれのモデルにアクションメソッドを追加する必要がなくなります。または少なくともNotifyアクションを持つクラスから継承します。分かりやすく読みやすいように、簡単な編集を行うだけです。あなたのQtyセッターへ

    //NotifyOfPropertyChange(); //NotifyOfPropertyChange(() => Sum); NotifyFromParent?.Invoke();

    を、そして:あなたのDataLineで

    は追加

    public DataLine(int a, System.Action action = null) 
        { 
        Qty = a; 
        NotifyFromParent = action; 
        } 
    
        public System.Action NotifyFromParent; 
    

    は、あなたのViewModelにあなたが行くことができます。

    Data = new BindableCollection<DataLine> 
    { 
        new DataLine(1,() => RefreshAction()), 
        new DataLine(2,() => RefreshAction()), 
        new DataLine(4,() => RefreshAction()), 
        new DataLine(6,() => RefreshAction()) 
    }; 
    

    を私が言ったようにあなたはこれをもっと魅力的にすることができます。私が経験した限りでは、データグリッド内のセルを編集するときに集計データまたは外部データを更新するメカニズムを作成し、その編集の直後に更新を望む必要があります。

    +1

    これはまさに私が求めていたものでした。私は、 'Action'とベース' ctor'を持つ 'ObjectWithNotifyParent'の基本クラスを作った。これは、 'BindableCollection'が作成されたオブジェクトに対して使用されます。ありがとう。 –

    関連する問題