我正在尝试对 DataGridBoundColumn 进行子类化以创建显示 ComboBox 的子类。API 反映了 ComboBox 的:
<sdk:DataGrid x:Name="dataGrid1"
AutoGenerateColumns="False"
ItemsSource="{Binding Items}">
<sdk:DataGrid.Columns>
<controls:DataGridComboBoxColumn
Binding="{Binding SalutationId}"
SelectedValuePath="SalutationId"
DisplayMemberPath="SalutationName"
ItemsSource="{Binding Salutations, ElementName=UserControl}"
Header="Salutation"
/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
莫名其妙地,使用 XAML 绑定 ItemsSource 不起作用,但以编程方式执行此操作 - 即
private void BindSalutations()
{
SalutationColumn = (DataGridComboBoxColumn) this.dataGrid1.Columns[1];
BindingOperations.SetBinding(
SalutationColumn,
DataGridComboBoxColumn.ItemsSourceProperty,
new Binding("Salutations") { Source = this });
}
我确保 ItemsSource 被定义为 DependencyProperty,但无济于事。这是我的实现:
using System;
using System.Collections;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SlDataGridColumn.Controls
{
public class DataGridComboBoxColumn: DataGridBoundColumn
{
public DataGridComboBoxColumn()
: base()
{
}
#region ItemsSource Dependency Property
#if false
private IEnumerable _itemsSource;
public IEnumerable ItemsSource
{
get { return _itemsSource; }
set { _itemsSource = value; base.NotifyPropertyChanged("ItemsSource"); }
}
#else
/// <summary>
/// Get or Sets the ItemsSource dependency property.
/// </summary>
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); base.NotifyPropertyChanged("ItemsSource"); }
}
/// <summary>
/// Identifies the ItemsSource dependency property. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource",
typeof(IEnumerable),
typeof(DataGridComboBoxColumn),
new PropertyMetadata(null, OnItemsSourcePropertyChanged));
/// <summary>
/// ItemsSource changed handler.
/// </summary>
/// <param name="d">DataGridComboBoxColumn that changed its ItemsSource.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source = d as DataGridComboBoxColumn;
if (source != null)
{
var value = (IEnumerable)e.NewValue;
source.NotifyPropertyChanged("ItemsSource");
}
}
#endif
#endregion ItemsSource Dependency Property
#region SelectedValuePath Dependency Property
/// <summary>
/// Get or Sets the SelectedValuePath dependency property.
/// </summary>
public string SelectedValuePath
{
get { return (string)GetValue(SelectedValuePathProperty); }
set { SetValue(SelectedValuePathProperty, value); }
}
/// <summary>
/// Identifies the SelectedValuePath dependency property. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath",
typeof(string),
typeof(DataGridComboBoxColumn),
new PropertyMetadata("", OnSelectedValuePathPropertyChanged));
/// <summary>
/// SelectedValuePath changed handler.
/// </summary>
/// <param name="d">DataGridComboBoxColumn that changed its SelectedValuePath.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void OnSelectedValuePathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source = d as DataGridComboBoxColumn;
if (source != null)
{
var value = (string)e.NewValue;
source.NotifyPropertyChanged("SelectedValuePath");
}
}
#endregion SelectedValuePath Dependency Property
#region DisplayMemberPath Dependency Property
/// <summary>
/// Get or Sets the DisplayMemberPath dependency property.
/// </summary>
public string DisplayMemberPath
{
get { return (string)GetValue(DisplayMemberPathProperty); }
set { SetValue(DisplayMemberPathProperty, value); }
}
/// <summary>
/// Identifies the DisplayMemberPath dependency property. This enables animation, styling, binding, etc...
/// </summary>
public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register("DisplayMemberPath",
typeof(string),
typeof(DataGridComboBoxColumn),
new PropertyMetadata("", OnDisplayMemberPathPropertyChanged));
/// <summary>
/// DisplayMemberPath changed handler.
/// </summary>
/// <param name="d">DataGridComboBoxColumn that changed its DisplayMemberPath.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void OnDisplayMemberPathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var source = d as DataGridComboBoxColumn;
if (source != null)
{
var value = (string)e.NewValue;
source.NotifyPropertyChanged("DisplayMemberPath");
}
}
#endregion DisplayMemberPath Dependency Property
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
{
var cb = new ComboBox();
BindingOperations.SetBinding(cb, ComboBox.SelectedValueProperty, new Binding(this.Binding) { Source = dataItem });
BindingOperations.SetBinding(cb, ComboBox.ItemsSourceProperty, new Binding("ItemsSource") { Source = this });
BindingOperations.SetBinding(cb, ComboBox.DisplayMemberPathProperty, new Binding("DisplayMemberPath") { Source = this });
BindingOperations.SetBinding(cb, ComboBox.SelectedValuePathProperty, new Binding("SelectedValuePath") { Source = this });
return cb;
}
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
{
var cb = new ComboBox();
cb.DataContext = dataItem;
BindingOperations.SetBinding(cb, ComboBox.ItemsSourceProperty, new Binding("ItemsSource") { Source = this });
BindingOperations.SetBinding(cb, ComboBox.DisplayMemberPathProperty, new Binding("DisplayMemberPath") { Source = this });
BindingOperations.SetBinding(cb, ComboBox.SelectedValuePathProperty, new Binding("SelectedValuePath") { Source = this });
BindingOperations.SetBinding(cb, ComboBox.SelectedValueProperty, new Binding(this.Binding.Path.Path));
return cb;
}
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs args)
{
return args.OriginalSource;
}
}
}
示例项目源代码在这里