绑定到 XAML 中 WPF DataGridCell 的内容的问题 [英] Problems binding to a the content of a WPF DataGridCell in XAML

查看:15
本文介绍了绑定到 XAML 中 WPF DataGridCell 的内容的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用以下帖子实现绑定到动态对象列表的数据网格

I used the following post to implement a datagrid bound to a list of dynamic objects

将 DynamicObject 绑定到具有自动列生成的 DataGrid?

ITypedList 方法 GetItemProperties 工作正常,网格显示我描述的所有列.

The ITypedList method GetItemProperties works fine, a grid is displayed with all the columns I described.

我使用自定义 PropertyDescriptor 并覆盖了上面帖子中描述的 GetValue 和 SetValue 方法,我还在动态对象中实现了 TryGetMember 和 TrySetMember 方法.

I use a custom PropertyDescriptor and override the GetValue and SetValue methods as described in the above post, I also implement the TryGetMember and TrySetMember methods in the dynamic objects.

所以基本上我有一个 ComplexObject:DynamicCobject 和一个字段 Dictionary 和一个 ComplexObjectCollection 实现 ITypedList 和 IList.

so basically I have a ComplexObject:DynamicCobject with a field Dictionary and a ComplexObjectCollection implementing ITypedList and IList.

这一切都很好,除了当我将 DataGrid 的 itemsSource 绑定到集合时,单元格将显示 SimpleObject 类型名称,并且我实际上想要实现一个模板以在文本块中显示 SimpleObject 的属性值.

This all works fine except when I bind the itemsSource of the DataGrid to the collection, the cells will show the SimpleObject type name and I actually want to implement a template to show the property Value of the SimpleObject in a text block.

我使用了各种方法来尝试获取底层 SimpleObject,但没有任何效果,我总是获取该行的 ComplexObject.我正在使用自动生成的列,这似乎总是生成一个文本列,这可能是问题所在,但为什么我仍然无法从单元格属性的某处获取底层 SimpleObject?

I've used all sorts of methods to try and get the underlying SimpleObject but nothing works and I always get the ComplexObject for the row. I am using autogenerated columns and this always seems to produce a text column, this may be the problem but why cant I still get the underlying SimpleObject from somewhere in the cell properties?

以下是我理想的解决方案,但这不起作用.

Below would be my ideal solution but this does not work.

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="DefaultNodeTempate">
            <ContentControl Content="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                              Path=Content}">
                <ContentControl.Resources>
                        <DataTemplate DataType="local:SimpleObjectType">
                            <TextBlock Text="{Binding Value}" />
                        </DataTemplate>
                </ContentControl.Resources>
            </ContentControl>
        </DataTemplate>
    </Grid.Resources>
    <DataGrid ItemsSource="{Binding ElementName=mainWin, Path=DynamicObjects}">
        <DataGrid.Resources>
            <Style TargetType="DataGridCell">
                <Setter Property="ContentTemplate" Value="{StaticResource DefaultNodeTempate}" />
            </Style>
        </DataGrid.Resources>
    </DataGrid>
</Grid>

如有任何建议,我们将不胜感激.

Any suggestions would be much appreciated.

谢谢

基兰

推荐答案

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

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.

这篇关于绑定到 XAML 中 WPF DataGridCell 的内容的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆