Microsoft.UI.Xaml.Interop.INotifyCollectionChanged is missing from WinUI Win32 namespaces. Using the default ObservableCollection doesn't work with ItemsControls and implementing Windows.UI.Xaml.Interop.INotifyCollectionChanged throws _The application called an interface that was marshalled for a different thread. (0x8001010E (RPC_E_WRONG_THREAD))_
So what is the correct way to notify ItemsControl for a CollectionChanged and also which INotifyPropertyChanged works with Binding?
This is a duplicate of #1557 and originally #1981
This really should have been fixed before the preview though. ObservableCollection is fundamental to ALL user interfaces.
This is slightly different than the issues linked here. This is for a Win32 app which is going through CSWinrt which should have a solution for this issue. Looks like a CSWinrt bug. @stevenbrix for FYI
Can you share a repro app?
I'm not seeing a crash, but it doesn't seem to be working. I have a repro here that is using markup like this:
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Click="myButton_Click" x:Name="myButton">Click me</Button>
<ItemsControl ItemsSource="{x:Bind MyItems}"/>
<ItemsControl ItemsSource="{Binding MyItems}"/>
</StackPanel>
public MainWindow()
{
MyItems.Add("hi");
MyItems.Add("goodbye");
this.InitializeComponent();
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
MyItems.Add("clicked");
}
ObservableCollection<string> MyItems { get; } = new ObservableCollection<string>();
Not sure if this is related to https://github.com/microsoft/CsWinRT/issues/272
@stevenbrix Sorry for the delay. Forgot about this issue due to Build.
Exception is thrown if you try to create custom observable collection and implement Windows.UI.Xaml.Interop.INotifyCollectionChanged interface.
When using ObservableCollection there is no exception but changes are not reflected on the UI.
I spent some time with this issue, too while I realized that there is a problem with INotifyCollectionChanged in WinUI Win32.
I think that this is a must to have basic functionality. Could this be please somehow (fixed) prioritized for the next preview, so we could explore/try out WinUI 3 preview with more complex scenarios and help you to find another possible issues? This is a blocker for ItemsControl based controls in MVVM apps.
As a workaround I tried to raise NotifyPropertyChanged of the whole collection during item Added or Removed, but it didn't help.
```C#
NotifyPropertyChanged(nameof(Items));
//where Items is ReadOnlyObservableCollection
```XAML
<ListBox ItemsSource="{x:Bind ViewModel.ProductsListViewModel.Items, Mode=OneWay}" />
Thank you
I don't know why it works, however I found a workaround:
// Add this class
public static class BindingUtils
{
public static IEnumerable Fix(IEnumerable x) => x.OfType<object>();
}
<!-- Change binding expressions to use above class. Items is ObservableCollection<T>. -->
<!-- before -->
ItemsSource="{x:Bind ViewModel.Items}"
<!-- after -->
ItemsSource="{x:Bind local:BindingUtils.Fix(ViewModel.Items), Mode=OneWay}"
@runceel, thank you for the information! Do you have to specify OneWay
for the binding to work?
@stevenbrix, Yes, I need OneWay
to work the workaround.
Updating the binding might be triggered PropertyChanged
event of ObservableCollection<T>
.
I think the Fix
method returns a different instance every call, and then ItemsControl refresh all items.
@runceel @stevenbrix I tried a similar workaround. I created a new (Immutable) ObservableCollection during on Added/Removed notifications, but this is not good for performance IMO.
Proper MVU could maybe help in this case.
This issue should be fixed in WinUI3 Preview2. Thanks!
Most helpful comment
@stevenbrix Sorry for the delay. Forgot about this issue due to Build.
Exception is thrown if you try to create custom observable collection and implement Windows.UI.Xaml.Interop.INotifyCollectionChanged interface.
When using ObservableCollection there is no exception but changes are not reflected on the UI.