DataGridTemplateColumn的自定义控件 [英] Custom Control for DataGridTemplateColumn

查看:57
本文介绍了DataGridTemplateColumn的自定义控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试从 DataGridTemplateColumn 创建一个自定义控件,该控件将在我们的许多应用程序中重复使用。我遇到了一些问题,使自定义控件上的依赖项属性绑定并正确引发了属性更改通知。

I'm currently attempting to create a custom control out of a DataGridTemplateColumn that will be reused across many of our applications. I'm running into some issues getting a dependency property on the custom control to bind and raise the property changed notification correctly.

我目前拥有从<$ c继承的控件$ c> DataGridTemplateColumn xaml看起来像这样:

I currently have the control inheriting from DataGridTemplateColumn the xaml looks like this:

<DataGridTemplateColumn x:Class="Controls.DataGridDateColumn"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding SelectedDate}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <Grid FocusManager.FocusedElement="{Binding ElementName=DatePicker}">
                <DatePicker Name="DatePicker" HorizontalAlignment="Left" VerticalAlignment="Center" SelectedDate="{Binding SelectedDate}"/>
            </Grid>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>

后面的代码如下此

public partial class DataGridDateColumn : DataGridTemplateColumn
{

    public static readonly DependencyProperty SelectedDateProperty = 
        DependencyProperty.Register("SelectedDate", 
        typeof(DateTime?), 
        typeof(DataGridDateColumn),
        new FrameworkPropertyMetadata(null, OnSelectedDateChanged));

    private static void OnSelectedDateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGridDateColumn col = (DataGridDateColumn)d;
        col.SelectedDate = (DateTime?)e.NewValue;
    }

    public DateTime? SelectedDate {
        get { 
            return (DateTime?)GetValue(SelectedDateProperty); 
        }
        set { 
            SetValue(SelectedDateProperty, value);                
        }
    }      

    public DataGridDateColumn()
    {
        InitializeComponent();            
    }

}

当我拥有内部控件时我在首页上的数据网格,并尝试像这样< Controls:DataGridDateColumn Header = Policy Date SelectedDate = {Binding Path = PolicyDate} SortMemberPath = PolicyDate />绑定到SelectedDate

When I have the control inside of my data grid on the main page and attempt to bind to SelectedDate like this <Controls:DataGridDateColumn Header="Policy Date" SelectedDate="{Binding Path=PolicyDate}" SortMemberPath="PolicyDate" />

我在输出窗口中收到一个绑定错误,指出它找不到我所指的依赖项属性

I'm getting a binding error in the output window that states that it can't find the dependency property I'm referring to

System.Windows.Data Error: 40 : BindingExpression path error: 'SelectedDate' property not found on 'object' ''TestData' (HashCode=32071430)'. BindingExpression:Path=SelectedDate; DataItem='TestData' (HashCode=32071430); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

我最初的想法是,因为这是一个项目控制我需要以不同于我的方式注册依赖项属性,但是我找不到任何其他信息。

My initial thought is that because this is an items control I need to register the dependency property differently than I am, but I can't find any additional information.

我尝试创建自定义列的原因是因为我们正计划将一些特定的行为与几种不同类型的列相关联,以使用户在我们所有应用程序中的体验更加均一。因此,我希望能够处理自定义控件内部的行为,以便我们不必在每个使用它的数据网格上不断地将不同的事件挂接到模板上。

The reason I am attempting to create custom columns is because we are planning on having specific behaviors associated with a few different types of the columns in order to make the user experience more homogeneous across all of our apps. So I want to be able to handle the behavior inside of the custom control so that we don't have to constantly hook up the different events to the template on every data grid that uses it.

任何建议将不胜感激。

推荐答案

在解决了这个问题很多时间后,我最终还是创建一个自定义控件,该控件继承自 PresentationFramework 程序集中的 DataGridBoundColumn 。这比尝试使模板属性正确绑定要好得多。我相信它们没有约束力,因为列模板不是可视化树的一部分。根据我在框架代码中看到的内容,看起来好像发生了绑定被传递到生成的单元格的情况。因此,传播绑定的唯一真正方法是使用某种代理对象,该代理对象确实绑定了数据并将其映射到依赖项属性。很hacky。

After fighting with this issue for a good deal of time I ended up creating a custom control that inherits from the DataGridBoundColumn in the PresentationFramework assembly. This works much better than trying to get the template properties to bind correctly. I believe they were not binding because the column template is not part of the visual tree. Based on what I see in the framework code it looks like what happens is the binding is passed off on to the cell that is generated. So the only real way to propagate the binding would be to use some kind of proxy object that does get data bound and have it map that binding to the dependency property. Very hacky.

我建议未来的用户查看 DataGridTextColumn 代码在Microsoft的参考源上。并构建类似的东西供您自己使用。

I would suggest to future users to check out the DataGridTextColumn code on Microsoft's Reference Source. and build something similar for your own uses.

我最终从许多自定义控件的DataGridBound列继承过来。要注意的关键方法是 GenerateEditingElement GenerateElement PrepareCellForEdit 。它们都是事件处理程序,可让您操纵单元格的表示以及附加绑定和事件处理程序。

I ended up inheriting from the DataGridBound column for many of my custom controls. The key methods to pay attention to are GenerateEditingElement, GenerateElement and PrepareCellForEdit. They are all event handlers and allow you to manipulate the presentation of the cell as well as attach bindings and event handlers.

作为示例,这是我的一些代码自定义 DataGridDateColumn ,因为没有内置的,我想为我的应用程序提供具有特定行为的可重用版本:

As an example here is a chunk of code from my custom DataGridDateColumn, as there is no built-in one and I wanted a reusable version with specific behavior for my application:

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
    {
        DatePicker dp = new DatePicker();
        dp.Name = "datePicker";
        CustomControlHelper.ApplyBinding(dp, DatePicker.SelectedDateProperty, this.Binding);
        dp.PreviewKeyDown += DatePicker_OnPreviewKeyDown;
        return (FrameworkElement)dp;
    }

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
    {
        TextBlock tb = new TextBlock();
        CustomControlHelper.ApplyBinding(tb, TextBlock.TextProperty, this.Binding);            
        cell.TextInput += OnCellTextInput;            
        return (FrameworkElement)tb;
    }

    protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
    {
        DatePicker picker = editingElement as DatePicker;
        DateTime newValue = DateTime.Today;

        if (picker != null)
        {
            DateTime? dt = picker.SelectedDate;
            if (dt.HasValue)
            {
                newValue = dt.Value;
            }

        }            

        picker.Focus();
        return newValue;
    }       

这篇关于DataGridTemplateColumn的自定义控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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