2016-04-26 202 views
0

私は、簡単な操作を行うための小さなDataGridを持っています。フィールドは3:Number 1、2、およびResult Numberです。 データグリッドコードは次の通りである:ObservableCollectionのデータを変更するとDataGridデータが更新されないのはなぜですか?

<DataGrid x:Name="dgNumbers" ItemsSource="{Binding lstOperations, Mode=TwoWay}" CanUserAddRows="True" AutoGenerateColumns="False" CellEditEnding="dgNumbers_CellEditEnding"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Number 1" Width="*" Binding="{Binding N1, Mode=TwoWay}"/> 
     <DataGridTextColumn Header="Number 2" Width="*" Binding="{Binding N2, Mode=TwoWay}"/> 
     <DataGridTextColumn Header="Result" Width="*" Binding="{Binding Result, Mode=TwoWay}" IsReadOnly="True"/> 
    </DataGrid.Columns> 
</DataGrid> 

私は数1、数および結果を保つオブジェクトを作成しました。これは、クラスコードです:

public class Numbers 
{ 
    public decimal N1 { get; set; } 
    public decimal N2 { get; set; } 
    public decimal Result { get; set; } 
} 

私はのObservableCollectionを作ることバインディングを理解しようとするために、この小さな例を作りました。この例では 、私持ってイベントに次のコード:

私はデータ収集を変更し、この事実は、データグリッドに反映されているかどうかを知るにしようとしています何
public MainWindow() 
{ 
    InitializeComponent(); 
    lstOperations = new ObservableCollection<Numbers>(); 
} 

ObservableCollection<Numbers> lstOperations; 

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    Numbers n = new Numbers(); 
    n.N1 = 10; 
    n.N2 = 5; 
    n.Result = 15; 
    lstOperations.Add(n); 
    dgNumbers.ItemsSource = lstOperations; 
} 

private void dgNumbers_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) 
{ 
    foreach(var item in lstOperations) 
    { 
     item.Result = item.N1 + item.N2; 
    } 
} 

、可能な場合、どのように右のそれを行うには? 、可能でない場合、どのように似たようなものを達成するために?

+0

をバインドするとき、私のためにそれが動作するには、ビューに表示されるはずです。問題は、コレクション全体を変更したり、アイテムの単一のプロパティを変更したりする場合に発生します。どちらの場合も、私はあなたにINotifyPropertyChangedインターフェイスを使用するようアドバイスします。 PrismのBindableBaseクラスを使用することもできますが、あなたの場合は、既にMainWindowクラスを継承しているため、独自に実装を記述する必要があります。 – mikes

+0

クラスの仕組みは?あなたは私に例を教えていただけますか? – Richard

答えて

1

あなたはまた、NuGet Prism.CoreでインストールしてBindableBaseクラスを使用することができます。

using Prism.Mvvm; 
using System.Collections.ObjectModel; 
using System.Windows; 

namespace YourApplication 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      DataContext = new MainWindowViewModel(); 
     } 

     private void dgNumbers_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) 
     { 
      foreach (var item in (DataContext as MainWindowViewModel).LstOperations) 
      { 
       item.Result = item.N1 + item.N2; 
      } 
     } 
    } 

    public class MainWindowViewModel : BindableBase 
    { 
     private ObservableCollection<Numbers> _lstOperations; 

     public ObservableCollection<Numbers> LstOperations 
     { 
      get { return _lstOperations; } 
      set 
      { 
       _lstOperations = value; 
       OnPropertyChanged(); 
      } 
     } 

     public MainWindowViewModel() 
     { 
      _lstOperations = new ObservableCollection<Numbers>(); 
      Numbers n = new Numbers 
      { 
       N1 = 10, 
       N2 = 5, 
       Result = 15 
      }; 
      LstOperations.Add(n); 
     } 
    } 

    public class Numbers : BindableBase 
    { 
     private decimal _n1; 
     public decimal N1 
     { 
      get { return _n1; } 
      set { SetProperty(ref _n1, value); } 
     } 

     private decimal _n2; 
     public decimal N2 
     { 
      get { return _n2; } 
      set { SetProperty(ref _n2, value); } 
     } 

     private decimal _result; 
     public decimal Result 
     { 
      get { return _result; } 
      set { SetProperty(ref _result, value); } 
     } 
    } 
} 

あなたはまた、ビューにバインドを変更する必要が最後に:

<DataGrid x:Name="dgNumbers" ItemsSource="{Binding LstOperations, Mode=TwoWay}" CanUserAddRows="True" AutoGenerateColumns="False" CellEditEnding="dgNumbers_CellEditEnding"> 

BindableBaseをされる使用OnPropertyChanged( "propertyName")ではなく、SetterでOnPropertyChanged()を記述する必要がないため、実装でCallerMemberName属性が使用されるため、かなり簡単です。また、新しい値を設定し、必要に応じて(新しい値が実際に変更されたとき)、OnPropertyChangedイベントを呼び出すSetPropertyメソッドが存在するため、さらに優れています。

+0

私の無知を間違えて、DataGridのバインディングはどうですか? – Richard

+0

バインディングは、DataContextモデルを提供することによって行われています。そのプロパティに何かが設定されている場合、ViewはContextからすべてを取ります。コードの後ろにはありません – mikes

+0

Perfect!それはあなたの時間のおかげで、魅力のように動作します! – Richard

1

INotifyPropertyChangedを実装するクラスはありますか?

あなたはObservableCollection eventsを購読することができます。 CollectionChangeはおそらくトリックを行いますが、データバインディングを利用しません。

public MainWindow() 
{ 
    InitializeComponent(); 
    lstOperations = new ObservableCollection<Numbers>(); 
    lstOperations.CollectionChanged += MyCollectionChanged; 
} 

private MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
{ 
    dgNumbers.ItemsSource = lstOperations; 

} 

したがって、基本的なデータバインディングはこのようになります。

public class ModelView : INotifyPropertyChanged 
{ 

    public ModelView() 
    { 
    lstOperations = new ObservableCollection<Numbers>(); 
    lstOperations.CollectionChanged += new NotifyCollectionChangedEventHandler((obj, e) => { OnPropertyChanged("lstOperations "); }); 
    } 
//----------------- Implementing the interface here 
    public event PropertyChangedEventHandler PropertyChanged; 

    // Call this method when you want the GUI updated. 
    public void OnPropertyChanged(string PropertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(PropertyName)); 
    } 
//-------------------Your Properties----------------------------- 
    private ObservableCollection<Numbers> _lstOperations ; 

    public ObservableCollection<Numbers> lstOperations 
    { 
     get{return _lstOperations ;} 
     set 
     { 
     _lstOperations = value; 
     OnPropertyChanged("lstOperations"); 
     } 

    } 

ここで、上記のクラスには、バインドする変数が含まれています。これで、Datagridのdatacontextを設定する必要があります。

今、どこでも、あなたは Model.lstOperationsを操作 lstOperationsを操作している
// Need your model instance. 
private ModelView Model; 

public MainWindow() 
    { 
     InitializeComponent(); 
     Model = new ModelView(); 
     dgNumbers.DataContext = Model; 
    } 

+0

モデルの変更を取得するためにNumbersクラスのINotifyPropertyChangedを実装する必要があります。 PrismからのBindableBaseの使用を改善する( 'public class Numbers:BindableBase')。 – mikes

+0

真。バインディングを含めるように編集します。 –

+0

いいえ、私のクラスはINotifyPropertyChangedを実装していません。どのように使用できますか? – Richard

-1

ごとに追加または削除するよりも、私の愚かな先端を許していますが、データグリッドにバインドされたのObservableCollectionを持っている場合、私はそのようなリスト

public class ModelNumber 
{ 
    public decimal N1 { get; set; } 
    public decimal N2 { get; set; } 
    public decimal Result { get; set; } 
} 

public class ViewModelNumber : NotifyPropertyChanged, IDataErrorInfo 
{ 
    protected ModelNumber __dataModel = null; 


    #region ---constructor--- 


    public ViewModelNumber() 
    { 
     // model init 
     this.__dataModel = new ModelNumber(); 
    } 


    #endregion 
    #region ---accessoren model basis--- 


    public decimal N1 
    { 
     get 
     { 
      return this.__dataModel.N1; 
     } 
     set 
     { 
      if (this.__dataModel.N1 != value) 
      { 
       this.__dataModel.N1 = value; 
       this.OnPropertyChanged("N1"); 
      } 
     } 
    } 

    public decimal N2 
    { 
     get 
     { 
      return this.__dataModel.N2; 
     } 
     set 
     { 
      if (this.__dataModel.N2 != value) 
      { 
       this.__dataModel.N2 = value; 
       this.OnPropertyChanged("N1"); 
      } 
     } 
    } 

    public decimal Result 
    { 
     get 
     { 
      return this.__dataModel.Result; 
     } 
     set 
     { 
      if (this.__dataModel.Result != value) 
      { 
       this.__dataModel.Result = value; 
       this.OnPropertyChanged("N1"); 
      } 
     } 
    } 


    #endregion 
    #region ---validation--- 


    /// <summary>Gets an error message indicating what is wrong with this object.</summary> 
    public string Error 
    { 
     get { throw new NotImplementedException(); } 
    } 

    /// <summary>Gets the error message for the property with the given name.</summary> 
    public string this[string _columnName] 
    { 
     get 
     { 

      try 
      { 
       if (_columnName != null) 
       { 
        switch (_columnName) 
        { 
         default: 
          break; 
        } 
       } 

       return (null); 
      } 
      catch (Exception _except) 
      { 
       // mlog 
       Log.Exception(this.GetType().FullName, MethodBase.GetCurrentMethod().Name, _except); 

       return (null); 
      } 
     } 
    } 


    #endregion 
} 

ObservableCollection<ViewModelNumber> lstOperations; 
+0

それは実際にはフェリックス(と少し私)が書いたのと同じことです。 :) – mikes

+0

kaneschno mikes! –