rajatIIT rajatIIT - 1 month ago 15
C# Question

Unable to populate DataGrid

I am trying to build a datagrid where columns are generated dynamically (this works fine) but I am unable to create bindings for the columns which update automatically (something like INotifyPropertyChanged).

Creating columns dynamically and want to use dictionary elements for binding which can be modified/added dynamically. No errors seen in debug output of visual studio.

I think I am really missing something minor here.

clicking button does not populate the second column

clicking button does not populate anything

ViewModel:

class DataGridAttachedPropertyViewModel {


public ObservableCollection<DataGridColumn> ColumnCollection { get; set; }
public ObservableCollection<AttachedPropertyEmployee> SomEmployees { get; set; }

public ICommand myCommand { get; set; }
public DataGridAttachedPropertyViewModel() {

this.ColumnCollection = new ObservableCollection<DataGridColumn>();


DataGridTextColumn tc = new DataGridTextColumn();
tc.Header = "Sample Column";
// tc.Binding = new Binding("name");
Binding forCurrent = new Binding("SimpleDict[f]");
forCurrent.Mode = BindingMode.TwoWay;
tc.Binding = forCurrent;

DataGridTextColumn tt = new DataGridTextColumn();
tt.Header = "Column x";
// tc.Binding = new Binding("name");
Binding forTheCurrent = new Binding("SimpleDict[x]");
forTheCurrent.Mode = BindingMode.TwoWay;

tt.Binding = forTheCurrent;

myCommand = new DelegateCommand(ButtonBase_OnClick);

this.ColumnCollection.Add(tc);
this.SomEmployees = new ObservableCollection<AttachedPropertyEmployee>();
this.SomEmployees.Add(new AttachedPropertyEmployee("Rajat","Norwalk"));

this.SomEmployees.Add(new AttachedPropertyEmployee("Matthew", "Norwalk"));
}

public void ButtonBase_OnClick() {
foreach (var VARIABLE in SomEmployees) {
VARIABLE.SimpleDict["x"] = "x";
}
}

}


AttachedPropertyEmployee.cs

public class AttachedPropertyEmployee : INotifyPropertyChanged {

private Dictionary<string, string> dict;

public Dictionary<string, string> SimpleDict {
get { return this.dict; }
set
{
if (this.dict != value) {
this.dict = value;
this.NotifyPropertyChanged("SimpleDict");
}
}
}

public AttachedPropertyEmployee(string Name, string Address) {
this.SimpleDict = new Dictionary<string, string>();
SimpleDict["f"] ="b";
this.name = Name;
this.address = Address;
}

public string name;
public string address { get; set; }


public event PropertyChangedEventHandler PropertyChanged;

public void NotifyPropertyChanged(string propName) {
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}


XAML:

<Window x:Class="LearnInteractivity.LearnDataGridAttachedProperty"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:LearnInteractivity"
mc:Ignorable="d"
Title="LearnDataGridAttachedProperty" Height="300" Width="300">

<!--
Put a datargrid and an attached property and update columns dynamincally.

-->


<StackPanel>

<DataGrid
local:DataGridColumnsBehavior.BindableColumns="{Binding ColumnCollection}"
x:Name="dgg"
AutoGenerateColumns="False"
ItemsSource="{Binding SomEmployees}"></DataGrid>
<Button Content="Populate" Command="{Binding myCommand}"></Button>

</StackPanel>



Answer

I see two problems here.

The first is that Dictionary<TKey,TValue> doesn't implement INotifyCollectionChanged, so when you change values in it, no event is raised and the UI never knows about it. You could look for an ObservableDictionary<K,V> and use that (IIRC there are a few implementations around), or you can do it the quick and dirty way:

public void ButtonBase_OnClick() {
    foreach (var VARIABLE in SomEmployees) {
        VARIABLE.SimpleDict["x"] = "x";
        VARIABLE.NotifyPropertyChanged("SimpleDict");
    }
}

That will notify the grid that SimpleDict has changed.

The second problem is that in the DataGridAttachedPropertyViewModel constructor, you forgot to add tt to ColumnCollection.

    this.ColumnCollection.Add(tc);
    this.ColumnCollection.Add(tt);

More thoughts:

I would be more comfortable adding something like this to AttachedPropertyEmployee:

public void SetColumValue(string key, string value) {
    SimpleDict[key] = value;
    NotifyPropertyChanged("SimpleDict");
}

And use that in your loop instead:

public void ButtonBase_OnClick() {
    foreach (var VARIABLE in SomEmployees) {
        VARIABLE.SetColumnValue("x", "x");
    }
}

Incidentally, I'd change SimpleDict to Dictionary<String, Object> so you can support more types than just string, and leave formatting to the UI. And I might consider exposing a ReadOnlyDictionary<K,V> in the SimpleDict property, with the writable dictionary a private field -- so callers would have no choice but to use SetColumnValue(k,v) to set the column values.