Cysharp / ObservableCollections

High performance observable collections and synchronized views, for WPF, Blazor, Unity.
MIT License
461 stars 36 forks source link

WPF example is behaving weirdly #7

Closed dgellow closed 4 months ago

dgellow commented 2 years ago

Hi there,

First let me thank you for the massive and impressive work you did with this library! Observable collections are really something that should get more love in the .Net ecosystem :)

I noticed something strange with the WPF example that you provide. When I run it locally and press a few times on the "Insert" button, I get the following :

image

The first 3 lines (in red) correspond to the initial items inserted via AddRange and is the tuple (value, view), while the rest (in green) has been added by pressing the "Insert" button and is only the value.

I do not understand why there is a difference, do you have any idea what could be the reason?

I'm also questioning yielding tuples (value, view) when enumerating, instead of only views. Tuples cannot be used directly for <ListView ItemSource={...} />. Is there a reason for this choice?

yossiepon commented 2 years ago

SynchronizedView<T, TView> が通知する NotifyCollectionChangedEventArgs<T> が T 型のため WPF に渡される要素も T 型になっているのが原因のように思われます。

NotifyCollectionChangedEventHandler<TView> として TView 型コレクションの変更イベントにしてやるとうまくバインドされました。やっつけ実装

ビューが (T value, TView view) のタプルになっている理由はフィルタメソッドで両方見たいからではと推測しましたが、元コメントにあるように WPF で直接バインドできないのは不便に感じました。

※試してませんが NotifyCollectionChangedEventHandler<(T, Tvalue)> としたら Item2.~ で取れたりするのでしょうか。

-- In English (Google Translate)

It seems that the element passed to WPF is also T type because NotifyCollectionChangedEventArgs<T> notified by SynchronizedView<T, TView> is T type.

By modifying the type parameter to NotifyCollectionChangedEventHandler<TView>, it was successfully bound to a TView type collection change event. Rough implementation

I guess the reason the view is a tuple of (T value, TView view) is because it's convenient to be able to see both values in the filter method, but as the original comment says, it can't be bound directly in WPF. I felt inconvenient.

neuecc commented 2 years ago

ありがとうございます、そのとおりですね、このままではあまりに不便というのはもっともです……! いただいた案も含め、ちょっと考えてみたいです。


You're right, it's too inconvenient as it is. I'll consider about it.

yossiepon commented 2 years ago

こんな感じで書けるような、別の案を考えてみました。実装 google translate) I came up with another idea that could be written as:

ItemsView = list
        .ToSynchronizedCoupleView(x => $"({x}, {x}$)")  // IReadOnlyCollection<(T, TView)> -NotifyCollectionChangedEventHandler<(T, TView)>
        .ToSynchronizedSingleView()         // IReadOnlyCollection<TView> -NotifyCollectionChangedEventHandler<TView>
        .WithINotifyCollectionChanged();        // IReadOnlyCollection<TView>, INotifyCollectionChanged, INotifyPropertyChanged
github-actions[bot] commented 1 year ago

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 7 days.

dgellow commented 1 year ago

Could we reopen this issue? It was stale but the issue still exists.

neuecc commented 1 year ago

sorry for no longer repond it, I'll check it.

dbowser commented 1 year ago

This looks like it would work very well to provide an ObservableRingBuffer with the ability to load a large slice of data at once for a real time graph (SyncFusion) in WPF. However, it is very unclear to me how to bind to it from WPF. I have reread the documentation many times, especially for WPF. I don't see how I would bind to the collection or if I even can, especially relative to the issues in this thread. Could someone please provide a simple example of binding a View Component in WPF to this collection or provide any tips? Thank you!

daraber commented 1 year ago

This looks like it would work very well to provide an ObservableRingBuffer with the ability to load a large slice of data at once for a real time graph (SyncFusion) in WPF. However, it is very unclear to me how to bind to it from WPF. I have reread the documentation many times, especially for WPF. I don't see how I would bind to the collection or if I even can, especially relative to the issues in this thread. Could someone please provide a simple example of binding a View Component in WPF to this collection or provide any tips? Thank you!

ObservableRingBuffer<...> ringBuffer = new();
var view = ringBuffer.CreateView(value => ...).WithINotifyCollectionChanged();

Bind to the view.

daraber commented 1 year ago

This issue needs to be resolved to make the library usable with WPF bindings.

Sending either a tuple or the actual object makes it unusable with ListView or DataGrid controls since the column bindings completely break. One way around this is tediously implementing IValueConverters for each column that extract the desired property from either a tuple or the object.

github-actions[bot] commented 11 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 30 days.

github-actions[bot] commented 5 months ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 30 days.

neuecc commented 4 months ago

sorry for delayed response, we've released v2.0.0, it fixes this issue.

dgellow commented 4 months ago

Thanks @neuecc! ❤️