I am programming an app in WinUI 3 using C#.
There are some controls that have an ItemsSource property.
When I pass an IEnumerable into the ItemsSource and then change the IEnumerable, the control changes accordingly.
I now want to implement the same behavior in my custom UserControl.
I have the following code, but it only works with IEnumerables that implement INotifyCollectionChanged (eg. ObservableCollection).
WinUI supports IEnumerables that don't implement INotifyCollectionChanged.
How can I do the same?
Here is my code:
public sealed partial class MyUserControl : UserControl
{
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(MyUserControl), new PropertyMetadata(null));
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
private IEnumerable _oldItemsSource;
public MyUserControl()
{
this.InitializeComponent();
RegisterPropertyChangedCallback(ItemsSourceProperty, OnItemsSourceChanged);
}
private void OnItemsSourceChanged(DependencyObject sender, DependencyProperty prop)
{
if (prop == ItemsSourceProperty)
{
var newValue = (IEnumerable)sender.GetValue(ItemsSourceProperty);
if (_oldItemsSource is INotifyCollectionChanged oldCollection)
{
oldCollection.CollectionChanged -= OnCollectionChanged;
}
if (newValue is INotifyCollectionChanged collection)
{
collection.CollectionChanged += OnCollectionChanged;
}
_oldItemsSource = ItemsSource;
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Update the control here
}
}
WinUI 3 allows me to use a List (doesn't implement INotifyCollectionChanged) as an ItemsSource.
Changes made to the List affect the control.
This is the code inside a test page:
public TestPage()
{
this.InitializeComponent();
var list = new List<string> { "Item1", "Item2", "Item3" };
var bar = new BreadcrumbBar(); ;
bar.ItemsSource = list;
this.Content = bar;
list.Add("Item4");
// The BreadcrumbBar now has 4 elements.
}
No, it doesn't unless the
IEnumerableis anINotifyCollectionChanged.Try to call
list.Add("Item4")in an event handler after the control has been initially rendered if you don't believe me.For example, this code will not add "Item4" to the
BreadcrumbBarcontrol:Changing the type of
listtoObservableCollection<string>will make it work as expected.So your custom control is no worse than any built-in control in that sense. The source collection must notify the view somehow.