简体   繁体   中英

Binding a DataGridComboBoxColumn to the DataGrid's ItemsSource in C#

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).

I did something similar. I was using Winforms, so my solution may not work for you. However I'd suggest using something similar to this.

http://tech.pro/tutorial/776/csharp-tutorial-binding-a-datagridview-to-a-collection

Coupled with this.

http://www.codeproject.com/Articles/31418/Implementing-a-Sortable-BindingList-Very-Very-Quic

As I had everything working, then found I couldn't sort my datagridview.

I don't have my sourcecode handy, but the general idea was I'd create my comboboxes and textbox columns by hand, then bind my list to it.

After I'd run a function that'd iterate through each row and based on the index ( in my case my comboboxes were the last 3 columns ) I'd add the values for the combobox by hand first, then after those are added, I'd check the value of the combobox and set it to that.

I also included this function in the data error event, for when I added a new column. Also it would randomly crash if I was adding a new row, if I had the autosize set. I had to set these to default, do my editing, then reset it.

Wish I had code to provide, but it might put you on your way. If not when I go in to work tomorrow I'll post some. Comboboxes are a huge pain to work with.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM