WPF自定义DependencyProperty绑定-SetValue设置正确的值,但绑定的属性集收到null

时间:2019-01-07 10:04:16

标签: c# wpf binding wpf-controls dependency-properties

我的控件中的自定义DependencyProperty出现问题。让我解释一下:

我可以控制可检查项目的列表。我需要将属性绑定到IEnumerable SelectedItems。 SelectedItemsProperty填充的逻辑在控件内部,因此它不仅是简单的绑定。这是我的控件后面的代码:

    public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IEnumerable<object>), typeof(ButtonColumnFilter));

    public IEnumerable<object> SelectedItems
    {
      get { return (IEnumerable<object>)GetValue(SelectedItemsProperty); }
      set { Debug.WriteLine("SelectedItems has been set in ButtonColumnFilter - Count:{0}", value?.Count());
            SetValue(SelectedItemsProperty, value);
          }
     }

在这里,我会收到带有正确数目的所选项目的Debug消息,因此控件内部的逻辑运行良好。 XAML中的属性绑定在这里:

    <MESControls:ButtonColumnFilter CanSearch="True" CanSort="False" DisplayMemberPath="DisplayName"
ItemsSource="{Binding Path=FilterAdapter.Drivers, Mode=OneWay, IsAsync=True}"
OnApplyFilter="Drivers_ApplyFilter"
SelectedItems="{Binding Path=SelectedFilterDrivers, Mode=TwoWay}"/>

在我的代码中定义了属性:

public IEnumerable<Driver> SelectedFilterDrivers
        {
            get => _SelectedFilterDrivers;
            set
            {

                Debug.WriteLine("SelectedFilterDrivers has been set in PlannerFilterAdapter - Count: {0}", value?.Count());
                if (_SelectedFilterDrivers != value)
                {

                    _SelectedFilterDrivers = value;
                    NotifyPropertyChanged("SelectedFilterDrivers");
                }
            }
        }

!!!但是在这里我得到了调试信息'value == null'!!!

绑定运行良好,我想应该及时调用属性集。奇怪的是,控件内部的SetValue具有正确的值,但是在代码外部,属性设置的值为null。

有什么问题? 谢谢。

更新:

以下是更改控件内部的SelectedItems的代码:

private void CheckableItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {

            if (e.PropertyName == "IsChecked" && !_IsChecking)
            {
                _IsChecking = true;

                CheckableItem item = sender as CheckableItem;

                if(item.IsChecked == true && InnerItemsSource.Where(ci=>ci.Item.ToString() != SELECTALL).All(ci=>ci.IsChecked == true))
                {
                    InnerItemsSource.Single(ci => ci.Item.ToString() == SELECTALL).IsChecked = true;
                    SelectAllIsSelected = true;
                }
                else if (InnerItemsSource.Where(ci => ci.Item.ToString() != SELECTALL).All(ci=>ci.IsChecked == true) || InnerItemsSource.Where(ci => ci.Item.ToString() != SELECTALL).All(ci => ci.IsChecked == false))
                {
                    InnerItemsSource.Single(ci => ci.Item.ToString() == SELECTALL).IsChecked = false;
                    SelectAllIsSelected = false;
                } 
                else 
                {
                    InnerItemsSource.Single(ci => ci.Item.ToString() == SELECTALL).IsChecked = null;
                    SelectAllIsSelected = false;
                }

                SelectedItems = CheckedItems;

                NotifyPropertyChanged("IsFilterUsed");
                NotifyPropertyChanged("FilterIcon");


            }

            _IsChecking = false;
        }

public IEnumerable<object> CheckedItems
        {
            get
            {
                return InnerItemsSource?.Where(ci => ci.IsChecked == true && ci.Item.ToString() != SELECTALL).Select(ci => ci.Item);
            }

        }

但是,正如我所写的那样,控件内部设置的属性接收正确的值,而我猜想类型正确。 CheckedItems的返回值为IEnumerable'<< em> object >'。

感谢帮助。

value is IEnumerable<Driver>

调用堆栈情况

这是集合的可见计数,仅在调用堆栈中退后一步 Here is visible count of the collection just one step back in the call stack

调用堆栈的下一步-断点-值为null Next step of call stack - breakpoint - value is null 事实是,在这些步骤之间是一些外部代码-但我没有收到任何错误,也没有警告 The true is, that between theses steps is some external code - but I didn't get any error neither warning

更新-一些进展

我尝试将公共IEnumerable << em> Driver > SelectedFilterDrivers更改为

public IEnumerable<object> SelectedFilterDrivers
        {
            get => _SelectedFilterDrivers;
            set
            {

                Debug.WriteLine("SelectedFilterDrivers has been set in PlannerFilterAdapter - Count: {0}", value?.Count());
                if (_SelectedFilterDrivers != value)
                {

                    _SelectedFilterDrivers = (IEnumerable<Driver>)value;
                    NotifyPropertyChanged("SelectedFilterDrivers");
                }
            }
        }

我收到了正确数量的物品。因此,在重新键入集合中的项目期间存在一个问题。因此,我需要提出一种更好的方法,即如何保持SelectedItems使用通用IEnumerable << em> object >

的能力。

重要的是,IEnumerable << em> object >与简单的绑定(在这种情况下,ItemsSource-的确是,它只是OneWay绑定)一起很好地工作了

2 个答案:

答案 0 :(得分:0)

在不深入研究代码的情况下,您是否尝试过使用SetCurrentValue而不是SetValue

See this SO Answer

答案 1 :(得分:0)

没有从IEnumerable<object>IEnumerable<Driver>的隐式转换。您应该在控件中将SelectedItems设置为IEnumerable。

如果最终您不想将所选驱动程序列表实现为可观察的集合,并且希望在控件中侦听更改,则可以在控件方面尝试转换为INotifyCollectionChanged来为您提供事件。 / p>