【问题标题】:Binding ComboBox to DataGrid Entry将 ComboBox 绑定到 DataGrid 条目
【发布时间】:2014-09-04 21:44:09
【问题描述】:

问题已解决,但仍有疑问。见文末,或继续阅读上下文。

我正在尝试设置一个 WPF 数据网格,其中包含许多带有组合框的模板列。特别是我在数据绑定方面遇到了麻烦。

数据模型
首先,我有Entry,它包含4个属性:

  • Name
  • Customer
  • Color
  • Type

最有趣的属性是Color,它还有两个子属性:

  • ColorString
  • Index

目标
我需要创建一个数据网格,其中每一行对应一个Entry 对象。 Customer、Color 和 Type 属性都有允许选择动态填充选项的组合框。我需要将每个组合框的选定项绑定到条目的各自属性。

截图


问题:
如何正确设置数据网格和每个组合框的数据上下文?
对于数据网格,我以编程方式将数据上下文设置为 ObservableCollection 的一个实例。
private ObservableCollection<Entry> entries = new ObservableCollection<Entry>();

public MainWindow()
{
    InitializeComponent();

    entries.Add(new Entry("Foo", "Customer1", new MyColor("#00000000", 1), "Type1"));
    entries.Add(new Entry("Bar", "Customer2", new MyColor("#00000000", 1), "Type2"));
    LayerMapGrid.DataContext = entries; //Set data-context of datagrid
}

对于颜色组合框,我在 XAML 中使用 ObjectDataProvider

<Window.Resources>
    <ObjectDataProvider x:Key="Colors" ObjectType="{x:Type local:MyColor}" MethodName="GetColors"/>
</Window.Resources>

这就是我绑定 ObjectDataProvider 的方式

<ComboBox ItemsSource="{Binding Source={StaticResource Colors}}"/>

MyColor 类中,我创建了以下方法:

public static ObservableCollection<MyColor> GetColors()
{
    ObservableCollection<MyColor> colors = new ObservableCollection<MyColor>();
    //... Fill collection... (omitted for brevity)
    return colors;
}

好消息是上述所有代码都可以工作。然而,这是解决手头问题的好方法吗?

这是我的下一个更重要的问题:
如何绑定组合框的选定项以更新 ObservableCollection&lt;Entry&gt;

我知道我需要设置UpdateSourceTrigger="PropertyChanged",以便更新我的来源,即Entry 集合。

这是我当前用于设置整个数据网格的 XAML 代码。注意:我还没有实现客户和类型组合框。我真的只关心颜色组合框:

<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False" Name="LayerMapGrid">
        <DataGrid.Columns>

            <!--Name Column-->
            <DataGridTemplateColumn Header="Name">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Label Content="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.HeaderStyle>
                    <Style TargetType="DataGridColumnHeader">
                        <Setter Property="Control.HorizontalContentAlignment" Value="Center" />
                    </Style>
                </DataGridTemplateColumn.HeaderStyle>
            </DataGridTemplateColumn>

            <!--Customer Column-->
            <DataGridTemplateColumn Header="Customer">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox SelectedItem="{Binding CustomerName, UpdateSourceTrigger=PropertyChanged}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

            <!--Color Column-->
            <DataGridTemplateColumn Header="Color">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox ItemsSource="{Binding Source={StaticResource Colors}}" SelectedItem="{Binding Color, ElementName=LayerMapGrid, UpdateSourceTrigger=PropertyChanged}">
                            <ComboBox.ItemTemplate>
                                <DataTemplate>
                                    <DockPanel Margin="2">
                                        <Border DockPanel.Dock="Left" HorizontalAlignment="Right" BorderThickness="1" BorderBrush="Black" Margin="1" Width="10" Height="10">
                                            <Rectangle Name="ColorRec" Fill="{Binding ColorString}"/>
                                        </Border>
                                        <TextBlock Padding="4,2,2,2" Text="{Binding ColorString}" VerticalAlignment="Center"/>
                                    </DockPanel>
                                </DataTemplate>
                            </ComboBox.ItemTemplate>
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

            <!--Type Column-->
            <DataGridTemplateColumn Header="Type">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox SelectedItem="{Binding Type, UpdateSourceTrigger=PropertyChanged}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

非常感谢您的帮助。我已经用这个把头撞在墙上大约 16 个小时了。

-尼克·米勒

编辑:
我找到了解决方案(并且总是在请求帮助后立即找到),但我不明白它是如何工作的。

在 XAML 中,我已将组合框绑定更改为以下内容:

<ComboBox ItemsSource="{Binding Source={StaticResource Colors}}" SelectedItem="{Binding Color, UpdateSourceTrigger=PropertyChanged}">

这里到底发生了什么?

为什么组合框现在指的是数据网格的数据上下文?当我将 ItemsSource 设置为指向我的 ObjectDataProvider 时,这不会被覆盖吗?

【问题讨论】:

  • 你的问题很长!如果你再也没有收到我的消息,我就没有通过。
  • 哈哈,那是因为我想详细阐述。无论如何,我发现了问题,但对它为什么起作用感到困惑。看我帖子的结尾:)

标签: wpf data-binding combobox wpfdatagrid datagridtemplatecolumn


【解决方案1】:

如何正确设置数据网格和每个组合框的数据上下文?

你没有。通常在 WPF 中,我们在我们正在设计的UserControlWindow 上设置DataContext 属性,而不是在单个控件上。这样,所有视图中的控件都可以访问数据属性。

如何绑定组合框的选中项以更新 ObservableCollection?

再一次,你没有做你正在做的事。而不是使用ObjectDataProvider,您应该只在后面的代码中拥有ObservableCollection&lt;MyColor&gt; 类型的属性并直接绑定到它。您应该将public Entries 属性绑定到DataGrid.ItemsSource 属性,private entries 字段设置为DataContext。您确实需要通读 MSDN 上的 Data Binding Overview 页面以获得更多帮助。

MainWindow.xamlDataContext 设置为自身(这通常不是一个好主意):

public MainWindow()
{
    InitializeComponent();

    Entries.Add(new Entry("Foo", "Customer1", new MyColor("#00000000", 1), "Type1"));
    Entries.Add(new Entry("Bar", "Customer2", new MyColor("#00000000", 1), "Type2"));
    DataContext = this; //Set DataContext to itself so you can access properties here
}

然后在MainWindow.xaml:

<DataGrid ItemsSource="{Binding Entries}" ... />

DataGrid 的每一行中的DataTemplates 自动将数据绑定集合中的相关项设置为DataContext,因此您可以自动访问相关类的属性。再次......无需手动设置任何DataContexts。如果您还有其他问题,请阅读链接文章,因为答案就在那里。


更新>>>

让我们澄清一些事情......我不是你的私人导师,所以这将是我最后的回复。

如何克服组合框继承数据网格的数据上下文?

要将数据绑定到设置为Window.DataContext 的对象,您只需要使用有效的Binding Path 和一些基本逻辑:

<ComboBox ItemsSource="{Binding DataContext.MyColors, RelativeSource={RelativeSource 
    AncestorType={x:Type YourLocalPrefix:MainWindow}}}" />

【讨论】:

  • 感谢您的帮助。您是否建议我创建某种包装类来保存整个数据上下文?您说我应该设置窗口/用户控件的数据上下文,但您还说我不应该将上下文设置为自身。我假设这个包装类的实例会更合适。 (该死,我花了一半的工作日阅读该 MSDN 页面以了解我在做什么!:P)。顺便说一句,你知道为什么我的组合框的代码使用两个不同的数据上下文吗?我猜是因为组合框继承了数据网格的上下文,然后被覆盖了。
  • 该死的,我花了一半的工作日阅读那个 MSDN 页面来了解我在做什么! 没有什么好事是来之不易的。 你知道为什么我的组合框代码使用两种不同的数据上下文吗? 它不...只有一个DataContext 属性。 您是否建议我创建某种包装类来保存整个数据上下文? 这是习惯性的,尤其是在使用 MVVM 时,这就是它如此受欢迎的原因。但实际上,将一个对象数据绑定到DataContext 是有意义的,该对象具有您要在视图中绑定的所有属性。
  • 我创建了一个包含ObservableCollection&lt;Entry&gt;ObservableCollection&lt;MyColor&gt; 作为属性的包装类,并且我已经将MainWindow 的数据上下文设置为指向包装的一个实例。如何克服继承数据网格数据上下文的组合框?我只需要颜色集合的 1 个实例,我已经尝试通过以下方式访问它:{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=MyColors}。使用另一个组合框,当继承的数据上下文是我的包装类时,我已经能够访问颜色。
  • 哎呀,我又做了一次!...我修好了。当我指定源时,我说源是Window.MyColors 这是错误的,因为MyColors 存在于我的Window 的DataContext 属性中。这是正确的代码:{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.MyColors}
猜你喜欢
  • 2014-10-10
  • 1970-01-01
  • 1970-01-01
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
相关资源
最近更新 更多