Reputation: 588
I have a small DataGrid to do a simple operation. Fields are 3: Number 1, 2 and Result Numer. DataGrid code is as follows:
<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>
I created an object where I keep the number 1, the number and outcome. This is the class code:
public class Numbers
{
public decimal N1 { get; set; }
public decimal N2 { get; set; }
public decimal Result { get; set; }
}
I made this small example to try to understand the Binding that make the ObservableCollection. For this example, I have the following code in the event:
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;
}
}
What I am trying to know if changing a data collection, this fact is reflected in the DataGrid, if possible, how to do it right ?, if not possible, how to achieve something similar?
Upvotes: 0
Views: 66
Reputation: 63
forgive my stupid tip but for me it works when i bind such a list
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;
Upvotes: -1
Reputation: 1669
You can also install by NuGet Prism.Core and use the BindableBase class:
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); }
}
}
}
In the end you also have to change the Binding in the View:
<DataGrid x:Name="dgNumbers" ItemsSource="{Binding LstOperations, Mode=TwoWay}" CanUserAddRows="True" AutoGenerateColumns="False" CellEditEnding="dgNumbers_CellEditEnding">
Using BindableBase is quite easy because it takes the CallerMemberName attribute in the implementation, so you don't have to specify which property is being called (you write OnPropertyChanged() in the setter instead of OnPropertyChanged("propertyName")). And it's even better, because there is also the SetProperty method, which sets the new value AND calls OnPropertyChanged event only when needed (when the new value is really new, really changed).
Upvotes: 1
Reputation: 1675
Do you have a class which implements INotifyPropertyChanged
?
You can subscribe to ObservableCollection
events. CollectionChange
would probably do the trick but doesn't take advantage of data binding.
public MainWindow()
{
InitializeComponent();
lstOperations = new ObservableCollection<Numbers>();
lstOperations.CollectionChanged += MyCollectionChanged;
}
private MyCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
dgNumbers.ItemsSource = lstOperations;
}
So the basic data binding would go like this.
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");
}
}
Ok the class above now contains your variable you want to bind. Now you need to set your datacontext for the Datagrid.
// Need your model instance.
private ModelView Model;
public MainWindow()
{
InitializeComponent();
Model = new ModelView();
dgNumbers.DataContext = Model;
}
Now anywhere you are manipulating lstOperations
you manipulate Model.lstOperations
.
Upvotes: 1