C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ReactivePropertyについて

[トピック内 14 記事 (1 - 14 表示)]  << 0 >>

■89725 / inTopicNo.1)  ReactivePropertyについて
  
□投稿者/ アルハンブラ (1回)-(2018/12/18(Tue) 23:32:08)

分類:[C#] 

最近、C#+WPFでReactivePropertyを使ってMVVMを試しています。

ReactiveProperty自体は非常に良く出来たライブラリだと思いますが、配列(例 List<string>)を
ReactivePropertyに設定したときの動作で悩んでいるところがあります。

実際、

ReactiveProperty<List<string>> names = new ReactiveProperty<List<string>>();
List<string> list = new List<string>();

list.add( "Aさん");

names.Value = list;

とすることは出来ます。が、ここで、list.add( "Bさん")としても表示は更新されないため、
一度、新しくListを生成して

var list2 = new List<string>(list);

要素を追加、

list2.add( "Bさん" );

値を再設定

names.Value = list2;

のように、新しくList<string>を作り替えると表示も更新されます。

個人的にはListが更新されるたびに作り替えるのも微妙な気がします。
何か、良さそうな方法があるのでしょうか?

よろしくお願いします。
引用返信 編集キー/
■89726 / inTopicNo.2)  Re[1]: ReactivePropertyについて
□投稿者/ Hongliang (730回)-(2018/12/19(Wed) 00:11:28)
コレクションであればReactiveCollection<T>を使うのがよろしいのでは。
引用返信 編集キー/
■89727 / inTopicNo.3)  Re[2]: ReactivePropertyについて
□投稿者/ アルハンブラ (2回)-(2018/12/19(Wed) 06:53:11)
No89726 (Hongliang さん) に返信
> コレクションであればReactiveCollection<T>を使うのがよろしいのでは。

その手もあるのですが、元データはModel側でList<string>として持っておきたいです。

※ReactiveCollection<T>が用意されていることから判断すると、無理なのかなぁ。。。
引用返信 編集キー/
■89728 / inTopicNo.4)  Re[3]: ReactivePropertyについて
□投稿者/ Azulean (1021回)-(2018/12/19(Wed) 07:03:23)
2018/12/19(Wed) 07:06:11 編集(投稿者)

No89727 (アルハンブラ さん) に返信
> その手もあるのですが、元データはModel側でList<string>として持っておきたいです。
>
> ※ReactiveCollection<T>が用意されていることから判断すると、無理なのかなぁ。。。

List<T> 自体に要素が増えた・減った・置き換えられたことを通知する手段はないので、無理でしょう。
ReactiveProperty に限らず、「変化を通知する」仕組みがないと動かない世界なので…。

あるいは。
List<T> を実体として持ちつつ、INotifyCollectionChanged を実現する仲介クラスを自分で作るか。
その場合、List<T>.Add などの変更をした後に明示的にイベント発行が必要です。
引用返信 編集キー/
■89729 / inTopicNo.5)  Re[3]: ReactivePropertyについて
□投稿者/ かずき (3回)-(2018/12/19(Wed) 08:41:28)
変更通知されないものは検知しようがないので以下の方法が考えられます。
1. Model 側を List ではなく ObservableCollection にする。
2. List を作り直してる箇所を ReactiveProperty の ForceNotify 呼び出しに変える。(http://okazuki.jp/ReactiveProperty/features/ReactiveProperty/)
引用返信 編集キー/
■89730 / inTopicNo.6)  Re[4]: ReactivePropertyについて
□投稿者/ アルハンブラ (3回)-(2018/12/19(Wed) 10:22:35)
No89729 (かずき さん) に返信
> 変更通知されないものは検知しようがないので以下の方法が考えられます。
> 1. Model 側を List ではなく ObservableCollection にする。
> 2. List を作り直してる箇所を ReactiveProperty の ForceNotify 呼び出しに変える。(http://okazuki.jp/ReactiveProperty/features/ReactiveProperty/)

上記の2の方法を試していますが、ちょっと上手く動作させられていない状況です。
 → これは、もう少し、試してみます。

現状のコードでは、下記のかずきさんのblogを参考にして、modelに元データを置いて
viewmodelへinortifypropertychanged で変更通知を送ってます。

https://blog.okazuki.jp/entry/2015/11/21/235455

string 型ならmodelで変更してからpropertychangedを発行するとviewmodelの
reactivepropertyが変更通知を受け取って表示が更新されます。

List<string> でも同じようにviewで値を書き換えてpropertychanged
でviewmodelのreactivepropertyに変更通知が届くと思っていたのですが
ダメみたいです。

コレクションは、stringと同じ方法ではダメな理由が思いつかなくてとっても悩んだます。
引用返信 編集キー/
■89746 / inTopicNo.7)  Re[5]: ReactivePropertyについて
□投稿者/ アルハンブラ (4回)-(2018/12/19(Wed) 21:05:12)
> コレクションは、stringと同じ方法ではダメな理由が思いつかなくてとっても悩んだます。

試してみたところ、やはり最初に書いたとおりList<string> list = new List<string>();

のように新しくコレクションを作ってあげれば、model側からinortifyChangedを発行して

ReactivePropertyまで届くようです。

あと、ForceNortifyも使ってみましたが、残念ながら私のところではNGでした。

とりあえず、model側のコレクションを更新したい時にはList<string>を毎回newして

nortifyChangedを発行することでViewModelのReactivePropertyに通知するように

する予定です。



引用返信 編集キー/
■89757 / inTopicNo.8)  Re[6]: ReactivePropertyについて
□投稿者/ かずき (4回)-(2018/12/21(Fri) 01:35:25)
GitHubに最小限の再現コードとかってだせますか??
引用返信 編集キー/
■89776 / inTopicNo.9)  Re[7]: ReactivePropertyについて
□投稿者/ アルハンブラ (5回)-(2018/12/23(Sun) 13:09:08)
No89757 (かずき さん) に返信
> GitHubに最小限の再現コードとかってだせますか??

https://github.com/alhanbra/reactiveTest2

再現コードをGitHubへアップしてみました。

model ← List<string> (表示したい元データ)を持っています
viewModel ← model の List<string> をReactivePropertyへ変換して持っています

実行後にキーを押すと CCC という文字列を model で持っている List<string>に追加して InortifyPropertyChangedを発行します。

ただ、mainwindowxaml.cs のL.37のコメントをコメントアウトしないとCCCと言う文字は表示されません。

※動きを見る限り、ReactivePropertyは先頭アドレス(C#なので表現は微妙)を更新しないと
※InortifyPropertyChanged が発行されても更新されたと認識をしないのでは無いかと思われます。


引用返信 編集キー/
■89780 / inTopicNo.10)  Re[8]: ReactivePropertyについて
□投稿者/ かずき (5回)-(2018/12/25(Tue) 11:35:50)
ToReactiveProperty の mode を指定すると値が変わってなくても PropertyChanged を発行するようにできますが、それでも見た目には反映されませんでした。
多分 WPF がそういう動きをするのだと思います。

なので、一番 WPF 的に素直なのは List ではなく ObservableCollection を使うようにすることだと思います。PullRequestを送っておきました。
https://github.com/alhanbra/reactiveTest2/pull/1

あとは、この例だと Model で ObservableCollection を使って、それを ViewModel で公開するだけなら ReadOnlyObservableCollection で包んでしまうというのも ViewModel からコレクションを操作しない予定ならありかなと思います。
https://github.com/alhanbra/reactiveTest2/pull/2
引用返信 編集キー/
■89784 / inTopicNo.11)  Re[9]: ReactivePropertyについて
□投稿者/ アルハンブラ (6回)-(2018/12/25(Tue) 23:11:07)
No89780 (かずき さん) に返信
> ToReactiveProperty の mode を指定すると値が変わってなくても PropertyChanged を発行するようにできますが、それでも見た目には反映されませんでした。
> 多分 WPF がそういう動きをするのだと思います。

はい。そうだと思います。例えば、WritableBitmapを使って同じことをしても更新はされないのでWPFの動きがそうなっている。と解釈するしかないですね。

ただ、逃げ道はあるので困っている訳では無いですが、WPFのこの動作は正直、納得は出来ないです。
→ ObservableCollectionを使った場合は、例えば、10個の要素を更新したら10回のUpdateが発生することになる(まとめてUpdateは1回にしたい)。
→ まぁ、そんなことを気にする人はWin32でも使ってろ。というのがMSの認識なのかもしれないですが。。。

いずれにしても、ありがとうございました。頂いたアドバイスを元にもう少し考えてみます。




引用返信 編集キー/
■89802 / inTopicNo.12)  Re[10]: ReactivePropertyについて
□投稿者/ かずき (6回)-(2018/12/28(Fri) 01:41:39)
ObservableCollection使うと10回要素を追加すると10回変更通知は飛びますが描画処理は律儀10書いはされなかったと思いますよ。

引用返信 編集キー/
■89804 / inTopicNo.13)  Re[11]: ReactivePropertyについて
□投稿者/ かずき (7回)-(2018/12/28(Fri) 11:56:53)
上記回答は携帯からだったので大雑把でしたが参考情報を:

ObservableCollection を使うと 10 回 Add することで 10 回 CollectionChanged イベントが発行されます。そこには差分情報だけが含まれていて WPF は差分だけを更新します。
その更新処理も描画まで行われるのではなく裏の描画するために必要な情報を更新する形になります。なので、Add を 10 回したからといって 10 回描画が走るわけではないです。

WPF の描画は保持モードとかいうキーワードで調べると色々出てくるのですが、データ更新すると即描画という感じではないです。因みに公式ドキュメントはありますが機械翻訳なので英語が読めるのでしたらそちらで見た方がいいと思います。

https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/graphics-multimedia/wpf-graphics-rendering-overview#visual-rendering-behavior

また、UI に表示されない部分の要素の追加は UI の仮想化の仕組みで、そもそも描画処理すら走りません。

https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/advanced/optimizing-performance-controls#displaying-large-data-sets

もちろん、データを一度に追加する数が増えれば増えるほど WPF が CollectionChanged の内容を見て同期をとる処理のオーバーヘッドが大きくなりますが私の環境で 10 万件のデータを追加してみて 400ms 程度の差でした。
なので、大量データを追加しない限りは同期する処理がパフォーマンス劣化につながるとは考えにくいです。

因みに List をまるごと入れ替える手法では差分ではなく全入れ替えが必ず走るので下手したら差分更新より描画まわりで遅くなることもあると思います。

ObservableCollection で大量の項目を追加したい場合は ObservableCollection を継承して AddRange メソッドを定義して、その中で CollectionChanged イベントの発行を抑止ししつつ要素を追加して最後に Reset の CollectionChanged イベントを発行することも出来ます。
下記サイトだと、ちょっと強引ですが拡張メソッドとして AddRange を追加しています。

http://artfulplace.hatenablog.com/entry/2016/12/29/133950

ということで追加するたびに描画はされないことと、全入れ替えをすると必ず全体の再描画が走るので、そこらへんを鑑みて Add で差分更新にするのか、凄く大量のデータの追加なので描画はリフレッシュするかを使い分けるのが最適だと思います。

引用返信 編集キー/
■89806 / inTopicNo.14)  Re[12]: ReactivePropertyについて
□投稿者/ アルハンブラ (7回)-(2018/12/28(Fri) 22:28:05)
No89804 (かずき さん) に返信
> 上記回答は携帯からだったので大雑把でしたが参考情報を:

なるほど。そういうことであれば、Listを使った場合にはObservableCollectionと違って差分更新の仕組みを意図的に含めなかったというのは
なんとなく理由が想像できる気がします。

ただ、ReactivePropertyの動作として見た場合にListだと意図通りには動作出来ない。ということになるので、このあたりはReactivePropertyとして
もう少しわかりやすい形になると良いな。と素直に感じました。
(どうなると良いかは?ごめんなさい。今は no idea です)

今担当している業務では、どうしても配列(1次元や2次元)やWritableBitmapをvmに持つ必要があるので、ListやWritableBitmapではなく
ObservableCollectionを使うように少し方法を(年末年始の間に)考えてみたいと思います。

頂いた情報は、私の方では見つけ出すことが出来なかったので、そういう意味でとても助かりました。また、なにかうまい方法が思いついたときには
この場を借りてご紹介させて頂きたいと思いますので、よろしくお願いします。

引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ