I'm creating a DataGrid
programmatically and have to support ComboBoxColumns
, too.
After I create DataGrid
, I set it's ItemSource
to a collection of a collection of type BindableList<BindableDictionary>
. BindableDictionary
is a custom type. Each BindableDictionary
represents one tuple. It's key is always the name of a column and it's value is a custom class that contains a generic property called ActualValue
, a Dictionary<T, string>
called AllowedValues
and a boolean
that determines if AllowedValues
will be used to build a ComboBoxColumn
or a 'normal' column. Also that class implements INotifyPropertyChanged
and INotifyPropertyChanging
.
That stuff works, aside from the ComboBoxColumn, duh. My problem with the ComboBoxColumn is that I don't know how to get it to use the AllowedValues
object to fill it's ItemList and use the ActualValue
property to select the correct Value
from the AllowedValues
BindableDictionary
to fill the textarea.
As an example, this is how I bind a textbased column:
table.Columns.Add(new DataGridTextColumn() { Header = column.GUIName, DisplayIndex = column.Position, Binding = new Binding(column.Name + ".ActualValue") { UpdateSourceTrigger = UpdateSourceTrigger.Default, Mode = BindingMode.TwoWay, NotifyOnTargetUpdated = true, NotifyOnSourceUpdated = true, UpdateSourceExceptionFilter = new UpdateSourceExceptionFilterCallback(BindingExceptionHandler) } });
And yes, that works.
I tried to set the ItemsSource
property of the DataGridComboBoxColumn
to column.AllowedValues
and set the DisplayPath
to "Value"
which does at least display the correct content, but I've no clue how to bind to the ActualValue
property that is contained in the DataGrid
's ItemsSource
. Also that'd mean that all cells inside a column share the same selectable values, which could lead to problems in the future.
And if I try to bind everything like I did in the DataGridTextColumn
, nothing is displayed at all. Also there are no items to select.
It'd be awesome if someone has so much as a hint of what I could try.
edit
Just saw this: https://stackoverflow.com/a/2197004/937093, I tried that but then I get the following message in my output window:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=AllowedValues; DataItem=null; target element is 'DataGridComboBoxColumn' (HashCode=33493530); target property is 'ItemsSource' (type 'IEnumerable')
My code looks like this:
col = new DataGridComboBoxColumn() { Header = column.GUIName, SelectedValueBinding = new Binding(column.Name + ".ActualValue"), SelectedValuePath = "ActualValue" };
table.Columns.Add(col);
BindingOperations.SetBinding(col, DataGridComboBoxColumn.ItemsSourceProperty, new Binding("AllowedValues"));
edit 2 okay, found this website: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
I tried to apply the proxy binding stuff (even though I don't get how the Column is not part of the visual tree of the DataGrid...where else would it be?!) but it won't work. My code:
BindingProxy proxy = new BindingProxy() { Data = table.ItemsSource };
table.Resources.Add("proxy", proxy });
col = new DataGridComboBoxColumn() { Header = column.GUIName, SelectedValueBinding = new Binding("Data." + column.Name + ".ActualValue") { Source = proxy }, DisplayMemberPath = "Value", SelectedValuePath = "Key" };
table.Columns.Add(col);
BindingOperations.SetBinding(col, DataGridComboBoxColumn.ItemsSourceProperty, new Binding("Data." + column.Name + ".AllowedValues") });
Output in output window:
System.Windows.Data Error: 40 : BindingExpression path error: 'MyColumn' property not found on 'object' ''BindingList`1' (HashCode=55207835)'. BindingExpression:Path=Data.MyColumn.ActualValue; DataItem='BindingProxy' (HashCode=45660050); target element is 'TextBlockComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')
I understand the problem (it's trying to find the 'MyColumn' object in the BindingList) but I don't understand why that is happening (it should resolve to BindingList[iterator]["MyColumn"], since BindingList contains the BindableDictionary and that's exactly what happens for my 'normal' columns).