【问题标题】:why my SelectedItems dependency property always returns null to bound property为什么我的 SelectedItems 依赖属性总是返回 null 到绑定属性
【发布时间】:2015-11-18 05:21:19
【问题描述】:

我创建了一个包装 DataGrid 的 UserControl1(这是为了测试目的而简化的,实际场景涉及第三方控件但问题是相同的)。 UserControl1 在测试应用程序的 MainWindow 中使用,如下所示:

<test:UserControl1 ItemsSource="{Binding People,Mode=OneWay,ElementName=Self}"
                             SelectedItems="{Binding SelectedPeople, Mode=TwoWay, ElementName=Self}"/>

一切都按预期工作,除了在 DataGrid 中选择一行时,SelectedPeople 属性始终设置为 null。

行选择流程大致为:UserControl1.DataGrid -> UserControl1.DataGrid_OnSelectionChanged -> UserControl1.SelectedItems -> MainWindow.SelectedPeople

调试显示带有从 DataGrid 中选择的项目的 IList 正在传递给 SelectedItems 依赖项属性的 SetValue 调用。但是当随后调用 SelectedPeople 设置器(作为绑定过程的一部分)时,传递给它的值始终为 null。

这是相关的 UserControl1 XAML:

<Grid>
    <DataGrid x:Name="dataGrid" SelectionChanged="DataGrid_OnSelectionChanged" />
</Grid>

在 UserControl1 的代码隐藏中是 SelectedItems 依赖属性和 DataGrid SelectionChanged 处理程序的以下定义:

    public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(UserControl1), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged));
    public IList SelectedItems
    {
        get { return (IList)GetValue(SelectedItemsProperty); }

        set
        {
            SetValue(SelectedItemsProperty, value);
        }
    }

    private bool _isUpdatingSelectedItems;

    private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctrl = d as UserControl1;

        if ((ctrl != null) && !ctrl._isUpdatingSelectedItems)
        {
            ctrl._isUpdatingSelectedItems = true;

            try
            {
                ctrl.dataGrid.SelectedItems.Clear();
                var selectedItems = e.NewValue as IList;

                if (selectedItems != null)
                {
                    var validSelectedItems = selectedItems.Cast<object>().Where(item => ctrl.ItemsSource.Contains(item) && !ctrl.dataGrid.SelectedItems.Contains(item)).ToList();
                    validSelectedItems.ForEach(item => ctrl.dataGrid.SelectedItems.Add(item));
                }
            }
            finally
            {
                ctrl._isUpdatingSelectedItems = false;
            }
        }
    }

    private void DataGrid_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!_isUpdatingSelectedItems && sender is DataGrid)
        {
            _isUpdatingSelectedItems = true;

            try
            {
                var x = dataGrid.SelectedItems;
                SelectedItems = new List<object>(x.Cast<object>());
            }
            finally
            {
                _isUpdatingSelectedItems = false;
            }
        }
    }

这是 MainWindow 代码隐藏中 SomePeople 的定义:

    private ObservableCollection<Person> _selectedPeople;
    public ObservableCollection<Person> SelectedPeople
    {
        get { return _selectedPeople; }
        set { SetProperty(ref _selectedPeople, value); }
    }    

    public class Person
    {
        public Person(string first, string last)
        {
            First = first;
            Last = last;
        }

        public string First { get; set; }
        public string Last { get; set; }
    }

【问题讨论】:

  • 我可以知道 SelectedPeople 的类型是什么吗?

标签: c# wpf data-binding wpf-controls


【解决方案1】:

我遇到了同样的问题,我不知道原因,但我是这样解决的:

1) DP

public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(object), typeof(UserControl1),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemsChanged));

    public object SelectedItems
    {
        get { return (object) GetValue(SelectedItemsProperty); }
        set { SetValue(SelectedItemsProperty, value); }
    }

2) 网格事件

private void DataGrid_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var SelectedItemsCasted = SelectedItems as IList<object>;
        if (SelectedItemsCasted == null)
            return;

        foreach (object addedItem in e.AddedItems)
        {
            SelectedItemsCasted.Add(addedItem);
        }

        foreach (object removedItem in e.RemovedItems)
        {
            SelectedItemsCasted.Remove(removedItem);
        }
    }

3) 在包含 UserControl1 的 UC 中

属性:

public IList<object> SelectedPeople { get; set; }

构造函数:

    public MainViewModel()
    {
        SelectedPeople = new List<object>();
    }

【讨论】:

  • 密钥在您的 DataGrid_OnSelectionChanged 处理程序中,从现有绑定列表/集合中添加和删除。我的代码正在创建一个新列表并分配给依赖属性,然后导致重新绑定到由于类型冲突而失败但没有引发异常的 SelectedPeople,只返回一个 null。在客户端中保留我的其余代码完全相同的保留类型安全性。另外,依赖属性类型是 IList 而不是 object。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-14
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 2016-01-22
  • 1970-01-01
相关资源
最近更新 更多