My task is to implement a UWP DataGrid with dynamic columns. As the user adds and remove columns, I need to add and remove the corresponding properties during runtime from the ObservableCollection of objects the DataGrid ItemSource is bound to. For reference, all of these properties would be strings.
The best tool I’m aware of to solve this issue the ExpandoObject class. It implements INotifyPropertyChangedEvent interface, and I’ve confirmed that the PropertyChangedEvents are firing when I make changes to the data. However, when updating an item in the collection from codebehind, the change will not make it’s way to and update the UI.
For now, I’m just trying to get a proof of concept working, so this should be a relatively simple example. I also would note that after pressing the button, when you double click on the first cell, the value will update, indicating that the data is updating and just not making it to the UI. That’s the one issue I need to solve.
XAML code:
<Button
Click="TestUpdateFirstItem"
Content="Update Cell"/>
<DataGrid
x:Name="MyGrid"
ItemsSource="{x:Bind Items, Mode=TwoWay}"
AutoGenerateColumns="False">
</DataGrid>
C# code:
public MainPage()
{
Items = new ObservableCollection<ExpandoObject>();
for (var i = 1; i < 4; i++)
{
dynamic item = new System.Dynamic.ExpandoObject();
(item as INotifyPropertyChanged).PropertyChanged +=
new PropertyChangedEventHandler(HandlePropertyChanges);
item.first = i.ToString();
item.second = $"Item {i}";
item.third = DateTime.Now.AddDays(i).ToString();
Items.Add(item);
}
MyGrid.Columns.Add(new DataGridTextColumn { Header = "first", Binding = new Binding { Path = new PropertyPath("first"), Mode = BindingMode.TwoWay }, IsReadOnly = false });
MyGrid.Columns.Add(new DataGridTextColumn { Header = "second", Binding = new Binding { Path = new PropertyPath("second"), Mode = BindingMode.TwoWay }, IsReadOnly = false });
MyGrid.Columns.Add(new DataGridTextColumn { Header = "third", Binding = new Binding { Path = new PropertyPath("third"), Mode = BindingMode.TwoWay }, IsReadOnly = false });
}
private void TestUpdateFirstItem(object sender, RoutedEventArgs e)
{
var firstRow = (IDictionary<string, object>)Items[0];
if (firstRow.ContainsKey("first"))
firstRow["first"] = "Test Update Cell";
}
public ObservableCollection<ExpandoObject> Items
{
get { return (ObservableCollection<ExpandoObject>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register(nameof(Items), typeof(ObservableCollection<ExpandoObject>), typeof(MainPage), new PropertyMetadata(default(ObservableCollection<ExpandoObject>)));
Before Manipulation:
enter image description here
After Pressing Button and Double Clicking on Cell:
enter image description here
As you may see in the example, I’ve set the bindings for the columns to TwoWay. I also tried setting up other examples with my own custom class to ensure I wasn’t missing anything. Those tests confirmed that the issue is with ExpandoObject, or at least my understanding of it. The custom class I made implemented INotifyPropertyChangedEvent, which then resulted in the data updating the UI as expected. In a larger version of my example code, I’m able to add/remove columns as well as rows, and the data displays and binds correctly. The only issue I’m seeing is specifically is that changes directly to the data don’t display in the UI as expected.
This is my first post/question on stack overflow, so feel free to critique my presentation of the question for future reference. Any help would solving this issue would be appreciated.
Sharkken is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.