1

我有一个包含 ComboBox 的 DataGridCell。

我希望,当我触发它的“SelectionChanged”事件时,不同列的 CollectionViewSource(最终 - 在运行时,单元格)CellEditingTemplate 的资源应该根据该行的选定值填充数据。

也许是 DataTrigger、ActionTrigger、EventTrigger,也许是代码,XAML 我不在乎,我只需要一个解决方案。

非常感谢!

相关:DataGridCells 之间的访问控制,动态级联 ComboBoxes

4

1 回答 1

4

如果我正确理解您的问题,您将根据在 DataGrid 同一行中的另一个单元格中选择组合框来填充单元格中组合框的内容。如果是:

第一个解决方案(IMO 更可取)

创建一个表示行数据的 ViewModel(数据对象的简单包装器)。将目标 ComboBox 的 ItemsSource-property 绑定到IEnumerable您从 viewmodel 提供的 -property。将 Source-ComboBox 中的 SelectedItem 绑定到 ViewModel 的另一个属性。每次 ViewModel 中的源属性更改时,您都会更改 ViewModel 提供的列表的内容。

用于目标(列表)属性 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。在构造函数中也这样做。作为 DataGrid 的 ItemsSource,您提供 DataObjectVM 类的 IEnumerable,该类包装您要显示的所有项目。


VisualTreeHelper 的替代方法

如果要手动执行,请在 ComboBox.SelectionChangedEvent 处理程序后面的代码中注册,然后更改目标 ComboBox 手册的 ItemsSource。您将通过 EventArgs 获得的业务对象。您必须在可视化树中搜索的目标 ComboBox(使用 VisualTreeHelper)。DataGridTemplateColumn如果您使用该类并DataTemplate使用相应的 ComboBoxes添加 a ,也可以连接事件。

但我认为这真的不是很简单,而且很容易出错。上述解决方案要容易得多。

这是您可能正在寻找的代码:

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 这个位置比网格的资源容器更合适。

如果您不想这样做,请检查以下帖子的状态:

如何获取 DataTemplate 的逻辑树

于 2010-07-10T22:32:05.530 回答