【问题标题】:DataGridTemplateColumns, AutoGenerateColumns=true and binding to a DataTableDataGridTemplateColumns、AutoGenerateColumns=true 并绑定到 DataTable
【发布时间】:2023-03-19 03:56:01
【问题描述】:

我正在努力解决一系列问题。

  1. 我有一个动态数据集,我手动将其组装成一个 DataTable。
  2. 我必须自动生成列,因为数据不是静态的。
  3. 我需要将组合框的 ItemsSource 绑定到每个单元格中定义的 Observable 集合。

虽然我认为这很容易,但 ComboBox 在 DataView 中看不到 DataItem,而是尝试直接绑定到 DataView。

我在这里整理了一个示例项目:

https://github.com/5flags/DataGridBindingIssue

现在,显然是为了证明这个问题。此时我无法更改数据结构,因此任何解决方案都必须在 XAML 中完成。

要查看问题,请使用 Snoop(或等效项)查看 ComboBox 上的绑定错误。

DataGrid 的设置如下:

<DataGrid AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn" CanUserAddRows="False" x:Name="TheDataGrid" ItemsSource="{Binding Data}">
    <DataGrid.Resources>
        <DataTemplate x:Key="dataItemCellTemplate">
            <ComboBox SelectedValue="{Binding Path=SelectedOption, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  ItemsSource="{Binding Options}"/>
        </DataTemplate>
    </DataGrid.Resources>
</DataGrid>

自动生成的事件处理程序是:

private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyType == typeof(string))
    {
        var col = new DataGridTextColumn {Binding = new Binding(e.PropertyName), Header = e.PropertyName};
        e.Column = col;
    }
    else if (e.PropertyType == typeof(DataItem))
    {
        var col = new DataGridTemplateColumn
        {
            CellTemplate = (DataTemplate) TheDataGrid.FindResource("dataItemCellTemplate"),
            CellEditingTemplate = (DataTemplate)TheDataGrid.FindResource("dataItemCellTemplate"),
            Header = e.PropertyName
        };
        e.Column = col;
    }
}

组合上的绑定错误是:

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“DataRowView”(HashCode=22264221)上找不到“选项”属性。绑定表达式:路径=选项; DataItem='DataRowView' (HashCode=22264221);目标元素是 'ComboBox' (Name='');目标属性是“ItemsSource”(类型“IEnumerable”)

System.Windows.Data 错误:40:BindingExpression 路径错误:在“对象”“DataRowView”(HashCode=22264221)上找不到“SelectedOption”属性。 BindingExpression:Path=SelectedOption; DataItem='DataRowView' (HashCode=22264221);目标元素是 'ComboBox' (Name='');目标属性是“SelectedValue”(类型“对象”)

【问题讨论】:

  • 能否请您显示您的数据绑定 XAML?
  • 编辑了问题以包含更多信息。
  • 您能否确认您的DataTable 中有一个名为Options 的列和一个名为SelectedOption 的列?
  • 单元格中的DataItem上面有SelectedOption和Options。
  • “数据项”是什么意思?我以为你说你正在使用DataTable...你的意思是DataRow?是什么让您认为Binding 正在到达DataView? Visual Studio 中的Output 窗口出现什么错误?

标签: c# wpf wpfdatagrid


【解决方案1】:

将您的 XAML 修改为:

<DataGrid AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn" CanUserAddRows="False" x:Name="TheDataGrid" ItemsSource="{Binding Data}">
    <DataGrid.Resources>
        <DataTemplate x:Key="dataItemCellTemplate">
            <ComboBox ItemsSource="{Binding [Option].Options}" SelectedValue="{Binding [Option].SelectedOption, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGrid.Resources>
</DataGrid>

其中[Option] 指的是DataView 的列,您在其中存储了您的自定义DataItem 对象。

【讨论】:

  • 谢谢,这在我创建的演示应用程序中运行良好,但在实际应用程序中,直到运行时我才知道列。你的回答让我走上了正确的道路。
【解决方案2】:

Dusan 的回答让我走上了正轨。因为直到运行时我才知道列名,所以我也必须在运行时创建数据模板。其实并不难。

private DataTemplate GetDataTemplate(string columnName)
{
    string xaml = "<DataTemplate><ComboBox SelectedValue=\"{Binding Path=[" + columnName +
                  "].SelectedEnumeratedElementItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}\"" +
                  " ItemsSource=\"{Binding Path=[" + columnName +
                  "].Items}\" DisplayMemberPath=\"Name\"/></DataTemplate>";

    var sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
    var pc = new ParserContext();
    pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
    pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
    var datatemplate = (DataTemplate)XamlReader.Load(sr, pc);

    return datatemplate;
}

【讨论】:

    【解决方案3】:

    我不知道如何使用来自XAML 资源的DataTemplate 执行此操作,但是使用代码中创建的DataTemplate 对我来说效果很好。

    private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
    {
        System.Windows.Controls.DataGridTemplateColumn templateColumn = new System.Windows.Controls.DataGridTemplateColumn();
        templateColumn.Header = e.PropertyName;
    
        DataTemplate template = new DataTemplate();
        FrameworkElementFactory factory = new FrameworkElementFactory(typeof(StackPanel));
        template.VisualTree = factory;
        FrameworkElementFactory childFactory = new FrameworkElementFactory(typeof(TextBox));
        childFactory.SetBinding(TextBox.TextProperty, new Binding(e.PropertyName));
        factory.AppendChild(childFactory);
    
        templateColumn.CellEditingTemplate = template;
    
        template = new DataTemplate();
        factory = new FrameworkElementFactory(typeof(StackPanel));
        template.VisualTree = factory;
        childFactory = new FrameworkElementFactory(typeof(TextBlock));
        childFactory.SetBinding(TextBlock.TextProperty, new Binding(e.PropertyName));
        factory.AppendChild(childFactory);
        templateColumn.CellTemplate = template;
    
        e.Column = templateColumn;
    }
    

    【讨论】:

      猜你喜欢
      • 2018-12-03
      • 2016-03-15
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-08
      • 1970-01-01
      • 2012-05-15
      相关资源
      最近更新 更多