且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

绑定到 XAML 中 WPF DataGridCell 的内容的问题

更新时间:2023-10-07 08:16:52

于是我发现解决方案是在后面的代码中做一些工作.

So I found the solution was to do some work in the code behind.

在 AutoGeneratingColumn 事件中创建一个带有内容控件和自定义模板选择器的 DataTemplate(我在 Xaml 中创建了选择器并将其作为资源找到).

In the AutoGeneratingColumn event create a DataTemplate with a content control and a custom template selector (I create the selector in Xaml and found it as a resource).

以e.PropertyName为路径为ContentControl的ContentProperty创建绑定

Create a binding for the ContentProperty of the ContentControl with e.PropertyName as the path

创建一个新的 DataGridTemplateColumn 并将新列 CellTemplate 设置为您的新 DataTemplate

Create a new DataGridTemplateColumn and set the new columns CellTemplate to your new DataTemplate

将 e.Column 替换为您的新列,然后将单元格数据上下文绑定到该列的动态属性.

replace e.Column with your new column and hey presto the cells datacontext bind with the dynamic property for that column.

如果有人对此有任何改进,请随时分享您的想法.

If anyone has any refinement to this please feel free to share your thoughts.

谢谢

根据要求为我的解决方案提供一些示例代码

As requested some sample code for my solution

自定义模板选择器:

public class CustomDataTemplateSelector : DataTemplateSelector
{
    public List<DataTemplate> Templates { get; set; }

    public CustomDataTemplateSelector()
        : base()
    {
        this.Templates = new List<DataTemplate>();
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        DataTemplate template = null;
        if (item != null)
        {
            template = this.Templates.FirstOrDefault(t => t.DataType is Type ? (t.DataType as Type) == item.GetType() : t.DataType.ToString() == item.GetType().ToString());
        }

        if (template == null)
        {
            template = base.SelectTemplate(item, container);
        }

        return template;
    }
}

XAML:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="ParentControl">
        <Grid.Resources>
            <local:CustomDataTemplateSelector x:Key="MyTemplateSelector" >
                <local:CustomDataTemplateSelector.Templates>
                    <DataTemplate DataType="{x:Type local:MyCellObject}" >
                        <TextBox Text="{Binding MyStringValue}" IsReadOnly="{Binding IsReadOnly}" />
                    </DataTemplate>
                </local:CustomDataTemplateSelector.Templates>
            </local:CustomDataTemplateSelector>
        </Grid.Resources>
        <DataGrid ItemsSource="{Binding Rows}" AutoGenerateColumns="True" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" >
        </DataGrid>
    </Grid>
</Window>

背后的代码:

private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    // Get template selector
    CustomDataTemplateSelector selector = ParentControl.FindResource("MyTemplateSelector") as CustomDataTemplateSelector;

    // Create wrapping content control
    FrameworkElementFactory view = new FrameworkElementFactory(typeof(ContentControl));

    // set template selector
    view.SetValue(ContentControl.ContentTemplateSelectorProperty, selector);

    // bind to the property name
    view.SetBinding(ContentControl.ContentProperty, new Binding(e.PropertyName));

    // create the datatemplate
    DataTemplate template = new DataTemplate { VisualTree = view };

    // create the new column
    DataGridTemplateColumn newColumn = new DataGridTemplateColumn { CellTemplate = template };

    // set the columns and hey presto we have bound data
    e.Column = newColumn;
}

可能有更好的方法来创建数据模板,我最近读到 Microsoft 建议使用 XamlReader,但当时我就是这样做的.此外,我还没有在动态类上测试过这个,但我相信它应该可以工作.

There may be a better way to create the data template, I have read recently that Microsoft suggest using a XamlReader but this is how I did it back then. Also I haven't tested this on a dynamic class but I'm sure it should work either way.