Подкласс DataGridBoundColumn в Silverlight
Я пытаюсь создать подкласс 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>
Необъяснимо, что привязка ItemsSource с использованием XAML не работает, но делает это программно - т.е.
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;
}
}
}
Пример исходного кода проекта находится здесь
1 ответ
DataGridColumn является объектом DependencyObject, а не FrameworkElement. Это различие важно для понимания проблемы. Смотрите здесь и здесь.
Следующая привязка не работает, поскольку DependencyObject не может выполнить привязку через ElementName.
<controls:DataGridComboBoxColumn
ItemsSource="{Binding Salutations, ElementName=UserControl}"
/>