I have a DataGrid
which is bounded to an ObservableCollection
. I have a list of data that is dynamic so items are being edited/added/removed from the list.
At first, I was clearing and adding the ObservableCollection
but then I found out that I can refresh the ObservableCollection
and I need to implement CollectionChanged
for that but I am not sure how so if any body can give some pointers or sample codes that would be great.
private List<OrderList> m_OrderListData = new List<OrderList>();
public List<OrderList> OrderListData
{
get => m_OrderListData;
private set => Set(ref m_OrderListData, value);
}
private ObservableCollection<OrderList> m_OrderListDataCollection;
public ObservableCollection<OrderList> OrderListDataCollection
{
get => m_OrderListDataCollection;
private set => Set(ref m_OrderListDataCollection, value);
}
...
...
m_OrderListDataCollection = new ObservableCollection<OrderList>(m_OrderListData as List<OrderList>);
...
...
foreach (OrderListViewModel Order in OrderList)
{
OrderListData.Add(new OrderList(Order.Description, Order.OrderId));
}
This is what i had before
OrderListData.Clear();
foreach (OrderListViewModel Order in OrderList)
{
OrderListData.Add(new OrderList(Order.Description, Order.OrderId));
}
m_OrderListDataCollection.Clear();
OrderListData.ToList().ForEach(m_OrderListDataCollection.Add);
XAML
<Label Content="OrderList"/>
<DataGrid Name="dgOrderList"
AutoGenerateColumns="False"
ItemsSource="{Binding Path=OrderListDataCollection}"
IsReadOnly="True"
SelectionMode="Single"
SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Width="Auto" Header="ID" Binding="{Binding OrderId}"/>
<DataGridTextColumn Width="*" Header="Description" Binding="{Binding OrderDescription}"/>
</DataGrid.Columns>
</DataGrid>
EDIT: OrderList Class
public class OrderList : INotifyPropertyChanged
{
private string m_OrderDescription;
private string m_OrderId;
public string OrderDescription
{
get => m_OrderDescription;
set => Set(ref m_OrderDescription, value);
}
public string OrderId
{
get => m_OrderId;
set => Set(ref m_OrderId, value);
}
#region Constructor
public OrderList()
{
}
public OrderList(string description, string id)
{
m_OrderDescription = description;
m_OrderId = id;
}
#endregion
#region INotifyPropertyChanged
/// <summary>Updates the property and raises the changed event, but only if the new value does not equal the old value. </summary>
/// <param name="PropName">The property name as lambda. </param>
/// <param name="OldVal">A reference to the backing field of the property. </param>
/// <param name="NewVal">The new value. </param>
/// <returns>True if the property has changed. </returns>
public bool Set<U>(ref U OldVal, U NewVal, [CallerMemberName] string PropName = null)
{
VerifyPropertyName(PropName);
return Set(PropName, ref OldVal, NewVal);
}
/// <summary>Updates the property and raises the changed event, but only if the new value does not equal the old value. </summary>
/// <param name="PropName">The property name as lambda. </param>
/// <param name="OldVal">A reference to the backing field of the property. </param>
/// <param name="NewVal">The new value. </param>
/// <returns>True if the property has changed. </returns>
public virtual bool Set<U>(string PropName, ref U OldVal, U NewVal)
{
if (Equals(OldVal, NewVal))
{
return false;
}
OldVal = NewVal;
RaisePropertyChanged(new PropertyChangedEventArgs(PropName));
return true;
}
/// <summary>Raises the property changed event. </summary>
/// <param name="e">The arguments. </param>
protected virtual void RaisePropertyChanged(PropertyChangedEventArgs e)
{
var Copy = PropertyChanged;
Copy?.Invoke(this, e);
}
/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Warns the developer if this object does not have
/// a public property with the specified name. This
/// method does not exist in a Release build.
/// </summary>
[Conditional("DEBUG")]
[DebuggerStepThrough]
protected virtual void VerifyPropertyName(string PropertyName)
{
// Verify that the property name matches a real,
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)[PropertyName] == null)
{
string ErrorMsg = "Invalid Property Name: " + PropertyName + "!";
if (ThrowOnInvalidPropertyName)
{
throw new Exception(ErrorMsg);
}
Debug.Fail(ErrorMsg);
}
}
/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail() is used
/// when an invalid property name is passed to the VerifyPropertyName method.
/// The default value is false, but subclasses used by unit tests might
/// override this property's getter to return true.
/// </summary>
protected virtual bool ThrowOnInvalidPropertyName { get; } = true;
If you just bind the ObservableCollection
to the Source
of your DataGrid
then it should work as intended.
When ever a new item is added or an item is being removed then your view will get notified to update his data.
To track actual changes you do not need to implement a CollectionChanged event of your list, but you'll have to make the actual objects inside the list observable. To make an object observable, you have to implement the INotifyPropertyChanged
interface.
Once the objects are observable, and a property sends out a PropertyChanged
notification, the observable collection will catch this.
Here is some quick sample code to get you started:
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propName));
}
}
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
}
public class Order : ObservableObject
{
private long _orderId;
public long OrderId
{
get { return _orderId; }
set { SetProperty(ref _orderId, value); }
}
private string _description;
public string Description
{
get { return _description; }
set { SetProperty(ref _description, value); }
}
}
(The ViewModel is supposed to be observable as well. Which I hope is already the case for you, else it would be pretty hard to have MVVM work.)
public class MyViewModel : ObservableObject
{
public MyViewModel()
{
//this is just an example of some test data:
var myData = new List<Order> {
new Order { OrderId = 1, Description = "Test1"},
new Order { OrderId = 2, Description = "Test2"},
new Order { OrderId = 3, Description = "Test3"}
};
//Now add the data to the collection:
OrderList = new ObservableCollection<Order>(myData);
}
private ObservableCollection<Order> _orderList;
public ObservableCollection<Order> OrderList
{
get { return _orderList; }
set { SetProperty(ref _orderList, value); }
}
}
<DataGrid Name="dgOrderList"
AutoGenerateColumns="False"
ItemsSource="{Binding OrderList, Mode=TwoWay}"
IsReadOnly="True"
SelectionMode="Single"
SelectionUnit="FullRow">
<DataGrid.Columns>
<DataGridTextColumn Width="Auto" Header="ID" Binding="{Binding OrderId}"/>
<DataGridTextColumn Width="*" Header="Description" Binding="{Binding OrderDescription}"/>
</DataGrid.Columns>
</DataGrid>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With