c# - DataGridTemplateColumn 的自定义控件

标签 c# wpf custom-controls dependency-properties

我目前正在尝试使用 DataGridTemplateColumn 创建自定义控件这将在我们的许多应用程序中重复使用。我在获取自定义控件的依赖属性以正确绑定(bind)和引发属性更改通知时遇到了一些问题。

我目前拥有继承自 DataGridTemplateColumn 的控件xaml 看起来像这样:

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

}

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

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

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')

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

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

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

最佳答案

在与这个问题斗争了很长时间之后,我最终创建了一个自定义控件,该控件继承自 PresentationFramework 程序集中的 DataGridBoundColumn。这比尝试让模板属性正确绑定(bind)要好得多。我相信它们没有约束力,因为列模板不是可视化树的一部分。根据我在框架代码中看到的情况,绑定(bind)似乎传递给了生成的单元格。因此传播绑定(bind)的唯一真正方法是使用某种代理对象,它确实获取数据绑定(bind)并将该绑定(bind)映射到依赖属性。非常骇人听闻。

我建议 future 的用户查看 DataGridTextColumn Microsoft 引用源上的代码。并构建类似的东西供您自己使用。

我最终从我的许多自定义控件的 DataGridBound 列继承。需要注意的关键方法是 GenerateEditingElementGenerateElementPrepareCellForEdit。它们都是事件处理程序,允许您操纵单元格的显示以及附加绑定(bind)和事件处理程序。

这里的一个例子是我的自定义 DataGridDateColumn 中的一段代码,因为没有内置代码,我想要一个具有我的应用程序特定行为的可重用版本:

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

关于c# - DataGridTemplateColumn 的自定义控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24642638/

相关文章:

c# - 哪个第 3 方契约(Contract)代码库最像 MS 的 .NET 4.0 库?

c# - 从 Windows C# Canon SDK 与 PTP 或 MTP 捕捉图片

c# - 在自定义控件的嵌套 DropDownList 中保存 ViewState

c# - 在哪里放置两个相关对象的业务逻辑?

c# - 内存流为空

c# - 折叠行时动态调整数据网格列的大小

C# WPF 移动窗口

c# - 在所有桌面上的任何窗口上的 WPF 中捕获 'text entering'

iphone - 他们是怎么做到的?...避免无聊、千篇一律的标准 iPhone 应用程序

c# - 创建自定义按钮控件