DataGridTemplateColumn的自定义控件

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

我目前有从DataGridTemplateColumninheritance的DataGridTemplateColumn ,xaml看起来像这样:

              

而背后的代码看起来像这样

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

当我在主页面上的数据网格内部有控件并尝试绑定到SelectedDate时,如此

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

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

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

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

任何建议,将不胜感激。

在与这个问题斗争了很长时间之后,我最终创建了一个自定义控件,它inheritance自PresentationFramework程序集中的DataGridBoundColumn 。 这比尝试正确绑定模板属性要好得多。 我相信它们没有绑定,因为列模板不是可视树的一部分。 基于我在框架代码中看到的情况,看起来发生的是绑定被传递到生成的单元格。 因此,传播绑定的唯一真正方法是使用某种代理对象,它确实获取数据绑定并让它映射绑定到依赖项属性。 非常hacky。

我建议未来的用户查看Microsoft的Reference Source上的DataGridTextColumn代码。 并为自己的用途构建类似的东西。

我最终inheritance了许多自定义控件的DataGridBound列。 要注意的关键方法是GenerateEditingElementGenerateElementPrepareCellForEdit 。 它们都是事件处理程序,允许您操作单元格的表示以及附加绑定和事件处理程序。

作为一个例子,这里是我的自定义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; } 

这里的消息显示,这看起来像一个类型转换问题,你可以做的是你可以创建一个valueconverter并可以在需要时手动应用,它将绑定值转换为你想要的特定类型,并将服务于你的目的。