DataGridTemplateColumns,AutoGenerateColumns = true并绑定到DataTable

时间:2013-12-10 11:25:28

标签: c# wpf wpfdatagrid

我正在努力应对各种各样的问题。

  1. 我有一个动态数据集,我手动组装成DataTable。
  2. 我必须自动生成列,因为数据不是静态的。
  3. 我需要将组合框的ItemsSource绑定到每个单元格中定义的Observable集合。
  4. 虽然我认为这很容易,但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)'上找不到'选项'属性。 BindingExpression:路径=选项; DataItem ='DataRowView'(HashCode = 22264221); target元素是'ComboBox'(Name =''); target属性是'ItemsSource'(类型'IEnumerable')

    System.Windows.Data错误:40:BindingExpression路径错误:'object'''DataRowView'(HashCode = 22264221)'上找不到'SelectedOption'属性。 BindingExpression:路径= SelectedOption; DataItem ='DataRowView'(HashCode = 22264221); target元素是'ComboBox'(Name =''); target属性是'SelectedValue'(类型'Object')

3 个答案:

答案 0 :(得分:3)

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

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;
}

答案 1 :(得分:2)

我不知道如何使用DataTemplate资源中的XAML来执行此操作,但对于我在代码中创建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;
}

答案 2 :(得分: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对象的列。