-
Notifications
You must be signed in to change notification settings - Fork 165
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
INotifyCollectionChanged implementation not compatible with ListCollectionView in WPF #3489
Comments
Hi @djymdmannen, thanks for your report. public class Wrapper<T> : IEnumerable<T>, INotifyCollectionChanged
{
private IEnumerable<T> inner;
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public Wrapper(IEnumerable<T> inner)
{
this.inner = inner;
(this.inner as INotifyCollectionChanged)!.CollectionChanged += Inner_CollectionChanged;
}
private void Inner_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// Break down the range actions here
CollectionChanged?.Invoke(this, e);
}
public IEnumerator<T> GetEnumerator()
{
return inner.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return inner.GetEnumerator();
}
} To make it easer to use you could even create an extension method: public static class Extension
{
public static IEnumerable<T> Wrap<T>(this IEnumerable<T> collection)
{
return new Wrapper<T>(collection);
}
} And then use the value returned by the method in the UI: UICollection = realm.All<RealmObj>().Wrap(); This is something I've wrote down quickly, so there could be some errors, but I hope that you got the point. I'm going to close this ticket, as we're not planning to work on this, but feel free to open a new one if you have other issues. |
@papafe, That's too bad. I was looking at that exact same work-around, but then it hit me that the wrapper needs to be applied to collection type properties as well? I'm assuming they all inherit from An example:
It's getting ugly. Where can I read more about the decision to not support WPF? I tried searching but came up short. |
@djymdmannen I can understand your frustration, it's a shame default collections in WPF don’t support range actions while To clarify, we closed this issue because we don’t feel comfortable adding the possibility of flattening the notifications in our SDK, as developers could incur in the risk of inconsistencies, especially if they modify the collection they are subscribed to in the notification callback. An alternative would be to raise Nevertheless, I've been experimenting a little bit on alternative (and hopefully more elegant) solutions to this problem, and I've come up with something based on converters. public class Wrapper: IEnumerable, INotifyCollectionChanged
{
private IEnumerable inner;
public event NotifyCollectionChangedEventHandler? CollectionChanged;
public Wrapper(IEnumerable inner)
{
this.inner = inner;
(this.inner as INotifyCollectionChanged)!.CollectionChanged += Inner_CollectionChanged;
}
private void Inner_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
CollectionChanged?.Invoke(this, e);
}
IEnumerator IEnumerable.GetEnumerator()
{
return inner.GetEnumerator();
}
} Then define a converter: public class WrapCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is IEnumerable ie)
{
return new Wrapper(ie);
}
//Shouldn't reach here
throw new Exception();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//Shouldn't reach here
throw new Exception();
}
} And finally use it in the xaml: <Window x:Class="TestWPF.MainWindow"
xmlns:local="clr-namespace:TestWPF"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:WrapCollectionConverter x:Key="WrapCollectionConverter"/>
</Window.Resources>
<Grid>
<ListView ItemsSource="{Binding Persons, Converter={StaticResource WrapCollectionConverter}}">
<ListView.View>
<GridView>
<GridViewColumn Header="Column 1" DisplayMemberBinding="{Binding Name}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window> This solution has the advantage of not needing to define additional properties in the model classes for collection properties. Besides, I have experimented with this a little, and it seems you also don't even need to flatten the collection yourself with this approach, as internally WPF uses I do not have much experience with WPF, so I could be missing some details here. What do you think of this approach, would it be reasonable for your use case? |
@papafe, Thank you, the solution looks interesting. I'll give it a try and I'll get back to you. |
@papafe, I've done some testing and it sure looks like this solution works. It is so much cleaner than having to duplicate collection properties and implement custom code that flattens the range actions. And not only that, the problem is also handled in the appropriate location (the view). And as far as work arounds go, I think this is as good as it gets, and you should mention this work around in the documentation. Great work, much appreciated! For future readers of this issue: if you're developing a WPF application and you bind to collections in Realm objects, you should use the suggested solution. If you do not, exceptions will be thrown in situations such as when adding two items to the collection in one transaction. |
@djymdmannen Glad to hear this is working for you! |
What happened?
I'm evaluating Realm and how we'd go about replacing SQLite as a database in our WPF application.
One thing that I've encountered is that the
INotifyCollectionChanged
implementation can lead to issues when bound to a control that usesListCollectionView
, such asListView
.Since
ListCollectionView
does not support range actions, it's very easy to trigger: add or remove two adjacent objects in a single transaction and you'll get aNotSupportedException
saying "Range actions are not supported.".ListCollectionView
throws the exception whenever it detects range actions for:NotifyCollectionChangedAction.Add
NotifyCollectionChangedAction.Remove
NotifyCollectionChangedAction.Replace
NotifyCollectionChangedAction.Move
Repro steps
IQueryable<T>
toListView
.ListCollectionView
throws an exception with a message saying "Range actions are not supported."Version
11.6.1
What Atlas Services are you using?
Local Database only
What type of application is this?
WPF
Client OS and version
Windows 11 23H2 22631.2792
Code snippets
No response
Stacktrace of the exception/crash you're getting
Relevant log output
No response
The text was updated successfully, but these errors were encountered: