Пользовательская привязка DependencyProperty WPF - SetValue устанавливает правильное значение, но набор связанных свойств получает значение NULL - PullRequest
0 голосов
/ 07 января 2019

У меня проблема с пользовательским 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);
          }
     }

Здесь я получаю сообщение отладки с правильным количеством выбранных элементов, поэтому моя логика внутри элемента управления работает хорошо. Недвижимость в 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 внутри элемента управления имеет правильное значение, но снаружи в коде установленное значение свойства равно нулю.

Что может быть не так? Спасибо.

UPDATE:

Вот код, который изменяет 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 <<1023 * object </em>> '.

Спасибо за помощь.

image">

Ситуация стека вызовов

Здесь виден счетчик всего шага назад в стеке вызовов. Here is visible count of the collection just one step back in the call stack

Следующий шаг стека вызовов - точка останова - значение равно нулю 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 - true, это просто привязка OneWay)

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Нет явного приведения от IEnumerable<object> до IEnumerable<Driver>. Вы должны установить SelectedItems как IEnumerable в вашем элементе управления.

Кстати, если, наконец, вы решите реализовать свой список выбранных драйверов как наблюдаемую коллекцию и хотите прослушать изменения в элементе управления, то на стороне элемента управления вы можете попытаться привести к INotifyCollectionChanged, который предоставит вам события.

0 голосов
/ 07 января 2019

Не вдаваясь в свой код слишком глубоко, вы пытались использовать SetCurrentValue вместо SetValue?

Смотрите этот SO-ответ

...