简体   繁体   English

在不同DataContext中具有两个组合框的MultiBinding

[英]MultiBinding with two Comboboxes in different DataContexts

I have the following datagrid that contains two comboboxes each contained in a data template. 我有以下数据网格,其中包含两个组合框,每个组合框都包含在数据模板中。

<DataGrid x:Name="FilterSelection" HorizontalAlignment="Stretch">

    <DataGrid.Resources>
        <DataTemplate x:Key="EntityComboboxTemp">
            <ComboBox x:Name="EntityCombobox"
                ItemsSource="{Binding DataContext.FilterVehicleEntities, RelativeSource={RelativeSource AncestorType=local:ExportView}}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction 
                            Command="{Binding DataContext.SelectedEntityCommand, RelativeSource={RelativeSource AncestorType=local:ExportView}}"
                            CommandParameter="{Binding ElementName=EntityCombobox, Path=SelectedItem}">
                        </i:InvokeCommandAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
        </DataTemplate>


        <DataTemplate x:Key="AttributeComboboxTemp">
            <ComboBox x:Name="AttributeCombobox"
                ItemsSource="{Binding DataContext.FilterAttributes, RelativeSource={RelativeSource AncestorType=local:ExportView}}">
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="SelectionChanged">
                        <i:InvokeCommandAction 
                            Command="{Binding DataContext.SelectedAttributeCommand, RelativeSource={RelativeSource AncestorType=local:ExportView}}">
                            <i:InvokeCommandAction.CommandParameter>
                                <MultiBinding Converter="{conv:FilterMultipleConverter}">
                                    <Binding ElementName="EntityCombobox" Path="SelectedItem"/>
                                    <Binding ElementName="AttributeCombobox" Path="SelectedItem"/>
                                </MultiBinding>
                            </i:InvokeCommandAction.CommandParameter>
                        </i:InvokeCommandAction>
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </ComboBox>
        </DataTemplate>
    </DataGrid.Resources>


    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Entity" CellTemplate="{StaticResource EntityComboboxTemp}" />
        <DataGridTemplateColumn Header="Entity Attribute" CellTemplate="{StaticResource AttributeComboboxTemp}"/>
    </DataGrid.Columns>
</DataGrid>

The problem lies in the multiple binding of the second combobox, namely the line: 问题在于第二个组合框的多重绑定,即该行:

Binding ElementName="EntityCombobox" Path="SelectedItem"/>

which should bind the selecteditem of the first combobox to the second combobox as commandparameter. 它将第一个组合框的选择项绑定到第二个组合框作为命令参数。 But I always get the Data binding error that EntityCombobox is unknown. 但是我总是会收到EntityCombobox未知的数据绑定错误。 How can I set the DataContext for this binding, is this even possible? 我如何为该绑定设置DataContext,这甚至可能吗?

My suggestion is to not do so much in your view. 我的建议是不要做太多您认为的事情。 I would recommend to do this logic in the ViewModel for the DataGrid. 我建议在DataGrid的ViewModel中执行此逻辑。

To start then I would create a view model for holding your filter selections. 首先,我将创建一个视图模型来保存您的过滤器选择。

Example: (please see comments for where to put logic for selection changes) 示例:(请参阅注释,将选择更改的逻辑放在何处)

public class FilterViewModel
{
    private string _vehicleEntity;
    public string VehicleEntity
    {
        get { return _vehicleEntity; }
        set
        {
            _vehicleEntity = value;
            //OnPropertyChanged() if you want
        }
    }

    private string _attribute;
    public string Attribute
    {
        get { return _attribute; }
        set
        {
            _attribute = value;
            //Add logic here to determine what to do with both Attribute and VehicleEntity
            //OnPropertyChanged() if you want
        }
    }
}

Then setup your overall View's ViewModel to hold a collection of the FilterModel along with the list of Vehicle options and Attribute options. 然后设置整个View的ViewModel,以保存FilterModel的集合以及Vehicle选项和Attribute选项的列表。

Example: 例:

public class MainWindowViewModel
{
    public ObservableCollection<FilterViewModel> Rows { get; }
    public ObservableCollection<string> FilterVehicleEntities { get; }
    public ObservableCollection<string> FilterAttributes { get; set; }

    public MainWindowViewModel()
    {
        Rows = new ObservableCollection<FilterViewModel>();

        FilterVehicleEntities = new ObservableCollection<string>()
        {
            "Vehicle 1",
            "Vehicle 2",
            "Vehicle 3",
        };

        FilterAttributes = new ObservableCollection<string>()
        {
            "Attribute 1",
            "Attribute 2",
            "Attribute 3",
        };
    }
}

Then make your view less complicated by just directly binding the selection to the properties. 然后,仅将选择内容直接绑定到属性,就可以减少视图的复杂性。 You will then get notified of selection changes as soon as the property updates (as marked in the comments for the FilterViewModel). 属性更新后,您将立即收到有关选择更改的通知(如FilterViewModel的注释中所标记)。

Example (full xaml): 示例(完整的xaml):

<Window x:Class="WpfApp1.MainWindow"
        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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow"
        Width="600"
        Height="500">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <DataGrid
            AutoGenerateColumns="False"
            ItemsSource="{Binding Rows}">
            <DataGrid.Columns>
                <DataGridComboBoxColumn
                    Header="Entity"
                    SelectedItemBinding="{Binding VehicleEntity, UpdateSourceTrigger=PropertyChanged}">
                    <!-- property changed so we get the change right after we select-->
                    <DataGridComboBoxColumn.ElementStyle>
                        <Style
                            TargetType="ComboBox">
                            <Setter
                                Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.FilterVehicleEntities}" />
                        </Style>
                    </DataGridComboBoxColumn.ElementStyle>
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style
                            TargetType="ComboBox">
                            <Setter
                                Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.FilterVehicleEntities}" />
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>

                <DataGridComboBoxColumn
                    Header="Entity Attribute"
                    SelectedItemBinding="{Binding Attribute, UpdateSourceTrigger=PropertyChanged}">
                    <!-- property changed so we get the change right after we select-->
                    <DataGridComboBoxColumn.ElementStyle>
                        <Style
                            TargetType="ComboBox">
                            <Setter
                                Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.FilterAttributes}" />
                        </Style>
                    </DataGridComboBoxColumn.ElementStyle>
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style
                            TargetType="ComboBox">
                            <Setter
                                Property="ItemsSource"
                                Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.FilterAttributes}" />
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

A ComboBox in a DataTemplate cannot refer to a ComboBox that is defined somewhere else using an ElementName binding because they are not in the same namescope . 一个ComboBox在一个DataTemplate不能引用一个ComboBox被定义在其他地方使用ElementName约束力的,因为它们不是在同一个名称范围

What you should do is to bind the SelectedItem property of the EntityCombobox to a source property, and then bind the CommandParameter property of the other ComboBox to the same source property. 您应该做的是将EntityComboboxSelectedItem属性绑定到源属性,然后将另一个ComboBoxCommandParameter属性绑定到相同的源属性。 For this to work, the class where the source property is defined must implement the INotifyPropertyChanged interface and raise change notifications and both ComboBoxes must also share the same DataContext . 为此,定义source属性的类必须实现INotifyPropertyChanged接口并引发更改通知,并且两个ComboBoxes还必须共享相同的DataContext

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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