0

我正在尝试对 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;
        }
    }
}

示例项目源代码在这里

4

1 回答 1

0

DataGridColumn 是 DependencyObject 而不是 FrameworkElement。这种区别对于理解问题很重要。见这里这里

以下绑定不起作用,因为 DependencyObject 无法通过 ElementName 进行绑定。

<controls:DataGridComboBoxColumn 
        ItemsSource="{Binding Salutations, ElementName=UserControl}"
        />
于 2013-10-02T00:28:27.847 回答