I have issue with custom DependencyProperty in my control. Let me explain:
I have control with list of the checkable items. I need property binding to the IEnumerable SelectedItems. The logic of SelectedItemsProperty filling is inside of control, so it is not just simple binding. Here is code behind of my control:
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);
}
}
Here I get Debug message with correct number of selected items, so my logic inside of control is working well. The property in XAML is binded here:
<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}"/>
And property is defined in my code here:
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");
}
}
}
!!! But here I get Debug message 'value == null' !!!
The binding is working well, and property set is called correctly in time i suppose. The weird is, that SetValue inside control has correct value, but outside in code the propert set value is null.
What can be wrong? Thanks.
UPDATE:
Here is code that changes SelectedItems inside control:
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);
}
}
But as I written, the property set inside control receive correct value and I guess correct type. The return value of CheckedItems is IEnumerable'<object>'.
Thanks for help.
Call stack situation
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
UPDATE - some progress
I tried change public IEnumerable<Driver> SelectedFilterDrivers to
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");
}
}
}
And I receive correct number of items. So there is an issue during retyping of items in collection. So I need to kick forward with the better way, how to keep ability for SelectedItems to use generic IEnumerable<object>
Important is, that IEnumerable<object> is working well with simple binding (in this case ItemsSource - true is, that it si just OneWay binding)