如何将自定义列的数据上下文设置为 ItemsSource 项目类型?

Posted

技术标签:

【中文标题】如何将自定义列的数据上下文设置为 ItemsSource 项目类型?【英文标题】:How to set custom column's datacontext to ItemsSource item type? 【发布时间】:2020-12-29 20:22:47 【问题描述】:

我试图了解框架的默认实现如何设法拥有 itemssource 项的数据上下文。具体来说,当设置了 DataGrid 的 ItemsSource(例如设置为 Foo 对象的集合)并且您在 DataGrid.Columns 属性中定义列时,DataGridTextColumn “Binding”属性需要来自 Foo 对象的属性。

以下代码可能更好地说明问题:

public class MainWindowViewModel

    public List<Foo> Foos  get; 


public class Foo

    public string FooDesignation  get; 

我非常简单的视图模型包含我的 DataGrid 的集合。然后我希望使用我自己的自定义列添加到 DataGrid 的列集合中:

public class CustomDataGridTextColumn : DataGridTextColumn

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        nameof(Text), 
        typeof(string), 
        typeof(CustomDataGridTextColumn), 
        new PropertyMetadata(default(string)));

    public string Text
    
        get => (string) this.GetValue(TextProperty);
        set => this.SetValue(TextProperty, value);
    

    private Binding _textBinding;

    public Binding TextBinding
    
        get => _textBinding;
        set => _textBinding = value;
    

生成的 XAML 如下所示(在 MainWindowView 中,数据上下文设置为 MainWindowViewModel 的实例)

<d:Window.DataContext>
    <x:Type Type="local:MainWindowViewModel" />
</d:Window.DataContext>
<Grid>
    <DataGrid ItemsSource="Binding Foos" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="Binding FooDesignation" />
            <local:CustomDataGridTextColumn Text="Binding FooDesignation" TextBinding="Binding FooDesignation" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

DataGridTextColumnBinding 属性可以毫无问题地绑定到 Foo (FooDesignation) 的属性,intellisense 也将此属性显示为一个选项。

我自己的 CustomDataGridTextColumn 的 Text 和 TextBinding 属性在绑定到同一个 FooDesignation 属性时会显示设计时和运行时错误。 Intellisense 向我展示了我的 MainWindowViewModel 的 Foos 属性作为选项(这很有意义,因为它显然没有继承 Foo 对象数据上下文)。

我的假设是它与 DataGridTextColumn 的 Binding 属性属于 Binding 类型这一事实有关,并且被配置为以某种方式运行可以。

我无法找到/理解这是如何实现的。任何人都可以对此有所了解吗?我的目标是让 Text/*TextBinding 属性的行为与 Binding 属性相同。

【问题讨论】:

【参考方案1】:

您可以将ItemsSource 设置为任何IEnumerable,并且DataGrid 将列的绑定应用于在列的GenerateElementGenerateEditingElement 方法中创建的可视元素(控件):

    protected abstract FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem);
    protected abstract GenerateElement(DataGridCell cell, object dataItem);

如您所见,这些方法接受从IEnumerable 检索的非类型化object。与所有其他绑定一样,使用反射解析实际属性值。这些列只是将绑定应用到生成的元素。

如果您想创建自定义列,您应该从 DataGridBoundColumn 或其任何子级继承,并按原样使用现有的 Binding 属性。

【讨论】:

感谢您的评论。但是,它并没有完全回答我的问题。即使我(正确地)从 DataGridBoundColumn 继承,我自己的属性的行为方式仍然与 Binding 属性不同(即自动绑定到可枚举中的当前项,即使有智能感知支持)。 Telerik 的 DataGrid 还实现了一个 DataMemberBinding 属性,该属性的行为类似于 Binding 属性,因此我必须缺少一些东西才能以相同的方式实现它。 @GeorgeB:如何表现相同?在 Visual Studio 中?你在用 Resharper 还是别的什么?

以上是关于如何将自定义列的数据上下文设置为 ItemsSource 项目类型?的主要内容,如果未能解决你的问题,请参考以下文章

如何以编程方式将自定义图像设置为 UIBarButtonItem

Swift:如何将自定义 UICollectionViewCell 设置为圆形?

Django 如何将自定义变量传递给上下文以在自定义管理模板中使用?

如何将自定义 ListAdapter 设置为 appwidget 中的列表视图?

如何从管理上下文数据中找到InlineModelAdmin?

如何将自定义字体设置为 android 工具栏的字幕?