Если я правильно понял ваш вопрос, вы заполните содержимое комбинированного списка в ячейке на основе выбора этого комбинированного списка в другой ячейке, которая находится в той же строке DataGrid.
Если да:
Первое решение (ИМО предпочтительнее)
Создайте ViewModel, который представляет данные строк (простая оболочка вокруг вашего объекта данных). Свяжите свойство ItemsSource целевого ComboBox с IEnumerable
-свойством, которое вы предоставляете из своей модели представления.
Свяжите SelectedItem из исходного ComboBox с другим свойством вашей ViewModel. Каждый раз, когда это свойство источника изменяется в вашей ViewModel, вы изменяете содержимое списка, предоставленного ViewModel.
Используйте для свойства desintation (list) a ObservableCollection<T>
. Свойство источника зависит от вас.
Вот примерный пример. Я называю класс VM (для ViewModel), но это ничего не меняет в вашем текущем решении. MVVM также можно использовать частично.
public class DataObjectVM : DependencyObject {
public static readonly DependencyProperty SelectedCategoryProperty =
DependencyProperty.Register("SelectedCategory", typeof(CategoryClass), typeof(DataObjectVM), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,delegate (DependencyObject d,DependencyPropertyChangedEventArgs e){
((DataObjectVM)d).SelectedCategoryChanged(e);
}));
ObservableCollection<ItemClass> _items=new ObservableCollection<ItemClass>();
void SelectedCategoryChanged(DependencyPropertyChangedEventArgs e) {
// Change here the contents of the _items collection.
// The destination ComboBox will update as you desire
// Do not change the _items reference. Only clear, add, remove or
// rearange the collection-items
}
// Bind the destination ComboxBox.ItemsSource to this property
public IEnumerable<ItemClass> DestinationItems {
get {
return _items;
}
}
// Bind to this property with the source ComboBox.SelectedItem
public CategoryClass SelectedCategory {
get { return (CategoryClass)GetValue(SelectedCategoryProperty); }
set { SetValue(SelectedCategoryProperty, value); }
}
}
Добавьте к этому классу конструктор, который принимает ваш объект данных и присваивает некоторые свойства-оболочки остальным свойствам, которые вы должны предоставить в DataGrid. Если их много, вы также можете создать одно свойство, которое предоставляет ваш объект данных и привязку непосредственно к нему. Не приятно, но это сделает работу.
Вы также можете (должны) предварительно инициализировать SelectedCategory с данными из вашего бизнес-объекта. Сделайте это также в конструкторе.
В качестве ItemsSource для DataGrid вы предоставляете IEnumerable класса DataObjectVM, который оборачивает все элементы, которые вы хотите показать.
Альтернативный способ с VisualTreeHelper
Если вы хотите сделать это вручную, зарегистрируйтесь в коде за обработчиком для ComboBox.SelectionChangedEvent и измените затем ItemsSource для конечного руководства ComboBox. Бизнес-объект, который вы получите с EventArgs. ComboBox назначения вы должны искать в визуальном дереве (используйте VisualTreeHelper). События также могут быть связаны, если вы используете класс DataGridTemplateColumn
и добавляете DataTemplate
с соответствующими полями ComboBox.
Но я думаю, что это действительно не очень просто сделать и может быть подвержено ошибкам. Приведенное выше решение намного проще.
Вот код, который вы, вероятно, ищете:
private void CboSource_SelectionChanged(object sender, SelectionChangedEventArgs e) {
ComboBox cbo = (ComboBox)sender;
FrameworkElement currentFe = VisualTreeHelper.GetParent(cbo) as FrameworkElement;
while (null != currentFe && !(currentFe is DataGridRow)) {
currentFe = VisualTreeHelper.GetParent(currentFe) as FrameworkElement;
}
if (null != currentFe) {
List<ComboBox> list = new List<ComboBox>();
FindChildFrameworkElementsOfType<ComboBox>(currentFe,list);
// Requirement 1: Find ComboBox
foreach (ComboBox cboFound in list) {
if (cboFound.Name == "PART_CboDestination") {
// This is the desired ComboBox
// Your BO is available through cbo.Found.DataContext property
// If don't like to check the name, you can also depend on the
// sequence of the cbo's because I search them in a deep search
// operation. The sequence will be fix.
}
}
List<DataGridCell> cells = new List<DataGridCell>();
FindChildFrameworkElementsOfType<DataGridCell>(currentFe,cells);
// Requirement 2: Find Sibling Cell
foreach (DataGridCell cell in cells) {
// Here you have the desired cell of the other post
// Take the sibling you are interested in
// The sequence is as you expect it
DataGridTemplateColumn col=cell.Column as DataGridTemplateColumn;
DataTemplate template = col.CellTemplate;
// Through template.Resources you can access the CollectionViewSources
// if they are placed in the CellTemplate.
// Change this code if you will have an edit cell template or another
// another construction
}
}
}
void FindChildFrameworkElementsOfType<T>(DependencyObject parent,IList<T> list) where T: FrameworkElement{
DependencyObject child;
for(int i=0;i< VisualTreeHelper.GetChildrenCount(parent);i++){
child = VisualTreeHelper.GetChild(parent, i);
if (child is T) {
list.Add((T)child);
}
FindChildFrameworkElementsOfType<T>(child,list);
}
}
И вот разметку, которую я использовал:
<DataGrid.Columns>
<DataGridTemplateColumn Header="Source" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="PART_CboSource" SelectionChanged="CboSource_SelectionChanged" ItemsSource="!!YOUR ITEMS SOURCE!!" SelectedItem="{Binding Category}">
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Destination">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Name="PART_CboDestination"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
Доступ к CollectionViewSource
Чтобы получить доступ к CollectionViewSource, поместите его в раздел ресурсов соответствующего DataTemplate, а не на панель, тогда у вас будет прямой доступ к ним. IMO это расположение в любом случае более подходящее, чем контейнер ресурсов в сетке.
Если вы не хотите этого делать, проверьте состояние следующего сообщения:
Как получить логическое дерево шаблона данных