如何在没有单元格模板的情况下使用DataGridComboBoxColumn

本文关键字:情况下 DataGridComboBoxColumn 单元格 | 更新日期: 2023-09-27 18:19:44

这应该是一件相当简单的事情我在这件事上绞尽脑汁太久了,
为什么ComboBox控件将显示类别列表,而DataGridComboBoxColumn控件在两者使用相同设置时拒绝显示类别列表

我是否必须为DataGridComboBoxColumn指定单元格模板才能使其工作,或者我在这里做错了什么?

复制的步骤很简单:
1.创建新的wpf项目并将其命名为WpfApplication10
2.将代码复制粘贴到MainWindow.xamlMainWindows.xaml.cs
3.运行项目-您会注意到ComboBox显示值,而DataGridComboBoxColumn不会显示值。

示例代码:

using System.Collections.ObjectModel;
using System.Windows;
namespace WpfApplication10
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Vm TheVm;
        public MainWindow()
        {
            TheVm = new Vm
            {
                VmCategories = new ObservableCollection<VmCategory>
                {
                    new VmCategory { CategoryName="Category1" },
                    new VmCategory { CategoryName="Category2" },
                    new VmCategory { CategoryName="Category3" },
                    new VmCategory { CategoryName="Category4" },
                    new VmCategory { CategoryName="Category5" },
                    new VmCategory { CategoryName="Category6" }
                },
                VmUsers = new ObservableCollection<VmUser>
                {
                    new VmUser { Name = "Gil" },
                    new VmUser { Name = "Dan" },
                    new VmUser { Name = "John" },
                }
            };
            InitializeComponent();
            DataContext = TheVm;
        }
    }
    public class Vm
    {
        public ObservableCollection<VmCategory> VmCategories { get; set; }
        public ObservableCollection<VmUser> VmUsers { get; set; }
    }
    public class VmUser
    {
        public string Name { get; set; }
        public VmCategory VmCategoryInfo { get; set; }
    }
    public class VmCategory
    {
        public string CategoryName { get; set; }
    }
}

示例XAML:

<Window x:Class="WpfApplication10.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:WpfApplication10"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        d:DataContext="{d:DesignInstance local:Vm, IsDesignTimeCreatable=True}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ComboBox Width="200" Height="40"
                  ItemsSource="{Binding DataContext.VmCategories, RelativeSource={RelativeSource AncestorType=Window}}"
                  DisplayMemberPath="CategoryName" />
        <DataGrid Grid.Row="1"
                  ItemsSource="{Binding VmUsers}" AutoGenerateColumns="False"
                  CanUserAddRows="True" CanUserDeleteRows="True" AreRowDetailsFrozen="False" SelectionMode="Single">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                <DataGridComboBoxColumn Header="Category" Width="120"
                                        SelectedItemBinding="{Binding VmCategoryInfo}"
                                        ItemsSource="{Binding DataContext.VmCategories, RelativeSource={RelativeSource AncestorType=Window}}"
                                        DisplayMemberPath="CategoryName"
                                        />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

重要更新
对于未来因同样问题而访问此页面的所有其他人,
如果你应用了解决方案,但它仍然没有解决你的问题-这意味着你有另一个问题导致了同样的问题-除非你很快就能解决,否则这是一个恶魔般的产物-我会解释:
就我而言,在更大的程序中,而不是我提供的示例中,
我需要解决的DataContext位于TabItem控件中,该控件本身不属于视觉树,因此它不起作用,因此实际上存在两个问题,一个是DataGridColumns不在视觉树中,另一个是,TabItem也不在视觉树中。。所以你应用了一个解决方案,但问题仍然存在,你认为这个解决方案有问题,而实际上你在不知不觉中处理了两个问题,导致了同一个错误
我最终通过创建一个网格来解决这个问题,该网格充当了保留TabItemDataContext的代理元素。

如何在没有单元格模板的情况下使用DataGridComboBoxColumn

<DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
            <DataGridComboBoxColumn Header="Category" Width="120" SelectedItemBinding="{Binding VmCategoryInfo}"
                                    DisplayMemberPath="CategoryName">
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType="{x:Type ComboBox}">
                        <Setter Property="ItemsSource" Value="{Binding Path=DataContext.VmCategories, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
                <DataGridComboBoxColumn.EditingElementStyle>
                    <Style TargetType="{x:Type ComboBox}">
                        <Setter Property="ItemsSource" Value="{Binding Path=DataContext.VmCategories, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
                    </Style>
                </DataGridComboBoxColumn.EditingElementStyle>    
            </DataGridComboBoxColumn>
        </DataGrid.Columns>

由于DataGridComboBoxColumn或任何其他支持的数据网格列不是数据网格可视化树的一部分,因此它们不会继承数据网格的DataContext。因为,它们不在可视化树中,所以任何使用RelativeSource获取DataContext的尝试都不起作用。

解决方案-您可以创建一个代理元素来绑定窗口的数据上下文;使用该代理元素来绑定DataGridComboBoxColumn的ItemsSource。例如:

<Window x:Class="WpfApplication10.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:WpfApplication10"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        d:DataContext="{d:DesignInstance local:Vm, IsDesignTimeCreatable=True}">
    <Grid>
        <Grid.Resources>
            <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <ComboBox Width="200" Height="40"
                  ItemsSource="{Binding DataContext.VmCategories, RelativeSource={RelativeSource AncestorType=Window}}"
                  DisplayMemberPath="CategoryName" />
        <ContentControl Visibility="Collapsed" Content="{StaticResource ProxyElement}"></ContentControl>
        <DataGrid Grid.Row="1"
                  ItemsSource="{Binding VmUsers}" AutoGenerateColumns="False"
                  CanUserAddRows="True" CanUserDeleteRows="True" AreRowDetailsFrozen="False" SelectionMode="Single">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" />
                <DataGridComboBoxColumn Header="Category" Width="120"
                                        SelectedItemBinding="{Binding VmCategoryInfo}"
                                        ItemsSource="{Binding DataContext.VmCategories, Source={StaticResource ProxyElement}}"
                                        DisplayMemberPath="CategoryName"
                                        />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>