WPF自定义DatagridColumn绑定问题
我正在尝试为我可以在我的应用程序中重用的数据网格定义一个新的列模板,但是当我尝试使用它时,我得到:
System.Windows.Data错误:2:找不到目标元素的管理FrameworkElement或FrameworkContentElement。 BindingExpression:路径= CanLogin; 的DataItem = NULL; target元素是’DataGridBetterCheckBoxColumn’(HashCode = 56040243); target属性是’isChecked’(类型’对象’)
XAML for Column:
代码背后:
using System.Windows; using System.Windows.Controls; namespace BACSFileGenerator.UserControls { public partial class DataGridBetterCheckBoxColumn : DataGridTemplateColumn { public object isChecked { get { return (object)GetValue(isCheckedProperty); } set { SetValue(isCheckedProperty, value); } } public static readonly DependencyProperty isCheckedProperty = DependencyProperty.Register("isChecked", typeof(object), typeof(DataGridBetterCheckBoxColumn), new PropertyMetadata(null)); public DataGridBetterCheckBoxColumn() { InitializeComponent(); } } }
然后我试着像这样使用它:
任何人都可以向我解释这样做的正确方法吗?
让我们说
public class ViewModel { public bool CanBeUsed {get;set;} public List Employees{get;set;} }
很少有人可能会让你困惑:
-
将只为属性实例化一个
DataGridBetterCheckBoxColumn
。 多条记录并不意味着属性的多列实例。 而是为每个DataGridColumn
创建多个DataGridColumn
。但
DataGridColumn
不是FrameworkElement
或Visual
因此它不会出现在VisualTree
,因为它不是FrameworkElement
所以它没有DataContext
属性。 没有DataContext
你的Binding
将如何工作? 问你自己。 由于此Column
无法设置其DataContext
,因此它必须具有ElementName
或Source
或RelativeSource
才能使其Binding
工作。现在,我们知道
DataGridColumn
只有一个实例,所以它的Binding
自然应该(使用)使用DataGridColumn
的DataContext
(集合属性将是其中的一部分)。现在,看看你的
Binding
,它的Source
/RelativeSource
哪里? 没有。 现在,RelativeSource
会在这里有意义吗? 由于DataGridColumn
没有出现在VisualTree
,因此RelativeSource
不适用于此处。 我们留下了Source
属性。 我们现在应该为Source
设置什么? 输入DataContext Inheritance
。DataContextinheritance
DataContext
inheritance仅适用于通过VisualTree
连接的FrameworkElement
。 因此,我们需要一种机制,我们可以使用这种机制将DataContext
转移到DataGridColumn
。 输入Binding Proxy
。public class BindingProxy : Freezable { #region Overrides of Freezable protected override Freezable CreateInstanceCore() { return new BindingProxy(); } #endregion public object Data { get { return (object)GetValue(DataProperty); } set { SetValue(DataProperty, value); } } // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc... public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null)); }
如果我们将此
BindingProxy
的实例声明为Resource
,我们可以获取Source
。现在,您将看到您讨厌的
Binding Error
消失了。 -
要使
CheckBox
绑定正常工作,您需要处理其Loaded
事件。代码:
void CheckBox_Loaded(object sender, RoutedEventArgs e) { Binding b = new Binding(); b.Path = new PropertyPath("isChecked"); b.Mode = BindingMode.TwoWay; b.Source = this; CheckBox cb = sender as CheckBox; BindingOperations.SetBinding(cb , CheckBox.IsCheckedProperty, b); }
但现在,我们在这里有一个逻辑问题。 我们所有的
CheckBox
现在都绑定到DataContext
属性CanBeUsed
,它将保持不变。 您可能认为CanBeUsed
应该是Employee
的属性,它是ItemsSource
而不是DataGrid
DataContext
。 因此,当您选中/取消选中任何CheckBox
,所有CheckBox
都会响应。
但是,我们希望将我们的isChecked
属性绑定到Employee
记录的某些属性,这将保留每个DataGridRow
差异。 所以,我们现在需要更改isChecked
的定义,之后整个代码如下所示:
public partial class DataGridBetterCheckBoxColumn : DataGridTemplateColumn { public BindingBase isChecked { get; set; } public DataGridBetterCheckBoxColumn() { InitializeComponent(); } void CheckBox_Loaded(object sender, RoutedEventArgs e) { CheckBox cb = sender as CheckBox; BindingOperations.SetBinding(cb , CheckBox.IsCheckedProperty, isChecked); } }
用法:
如果我错过任何一点,请告诉我。