質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
ReactiveX

ReactiveX(Rx、Reactive Extensions)は、リアクティブプログラミングが可能なライブラリ。Java/Android用のRxJava、JavaScript用のRxJSなどさまざまな言語向けに実装されています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

3188閲覧

ObservableCollection<T>からIObservable<bool>/ReactiveProperty<bool>を作りたい

ry188472

総合スコア74

ReactiveX

ReactiveX(Rx、Reactive Extensions)は、リアクティブプログラミングが可能なライブラリ。Java/Android用のRxJava、JavaScript用のRxJSなどさまざまな言語向けに実装されています。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1グッド

1クリップ

投稿2021/10/04 06:23

TINotifyPropertyChangedを実装している任意の型です。
ObservableCollection<T>に格納されているデータについて、条件を満たす場合にtrue、満たさない場合にfalseを発行するIObservable<bool>(正確にはReadOnlyReactiveProperty<bool>)を作りたいです。
簡単にできると思ったのですがやり方がわからなかったので、わかる方は教えていただければ幸いです。

C#

1public class MyData : BindableBase 2{ 3 public string Id { get => _id; set => SetProperty(ref _id, value); } 4 private string _id; 5} 6 7public class MyDataUserViewModel 8{ 9 // 例:2文字以上の場合true 10 public ReactiveProperty<bool> IsLargeLength { get; } 11 public MyDataUserViewModel() 12 { 13 // 変換したいデータのObservableCollection 14 var collection = new ObservableCollection<MyData>(); 15 collection.AddRange(Enumerable.Range(1, 10). 16 Select(i => new MyData { Id = i.ToString() }).ToArray()); 17 18 // うまくいかなかった例 19 // Anyの時点でboolになるのでダメ 20 IsLargeLength = collection.Any(d => d.Length >= 2).ToReadOnlyReactiveProperty(); 21 // これだとReadOnlyにならない 22 IsLargeLength = collection. 23 ToReactivePropertySlimAsSynchronized(c => c.Any(d => d.Length >= 2)); 24 } 25}

言語:C# 9.0

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ry188472

2021/10/04 07:19

コメントありがとうございます。CollectionChangedを使って、コレクションの増減時にbool値が発行されるReactivePropertyは作ることができました。 ただ、要素数が変わらずにMyDataのプロパティの変更時にもIObservable<bool>の値を発行したいので、ToReacitve~~のように一発変換することはできなさそうです。おそらくReactiveProperty<bool>は普通にnewして、CollectionChangedと各要素の値変更をそれぞれSubscribeして必要があればReactiveProperty<bool>を変更するのが良さそうですが、もっといい方法がありますかね?
Zuishin

2021/10/04 07:23

要素のプロパティの変化を知らなければならないのであれば、全ての要素を監視する以外にないと思います。 MyData をイミュータブルにできるのであれば、プロパティの変化の代わりに要素の取り替えが強制できるので、CollectionChanged で監視できます。 要素数が変わらなくても要素を取り替えれば発生するはずです。
ry188472

2021/10/04 07:44

なるほど、イミュータブルにして入れ替えさせるのは考えてなかったです。妙案ですね。 適当に回答を投稿してもらえればBAにしますが、どうしますか?
Zuishin

2021/10/04 07:52

実装して意図通り動くことが確認できたら自己解決してください。 それまでにより良い回答がつくかもしれませんし。
ry188472

2021/10/04 08:01

わかりました。ありがとうございます。
TN8001

2021/10/04 10:22

ObserveElementProperty拡張メソッドがあるんですが、逆に増減時の扱いがよくわかんないです^^;
TN8001

2021/10/05 13:02

次の質問と関係あるんですよね? それが解決すればこれも自動的に解決するってことですか? イミュータブルに方針転換したということなんでしょうが、編集が前提のDataGridにrecordを使うのは明らかに筋が悪いと思います。 ZuishinさんもまさかMyDataをDataGridに突っ込むとは思っていないでしょう。 技術的興味があってやってみたいということであれば、なにもいうことはありませんが^^; [C# - 完全コンストラクタパターンのコレクションをDataGridで編集するには|teratail](https://teratail.com/questions/305906#reply-429444 それよりもまずObserveElementPropertyを試してください。 完動コードを回答しているので5分で確認できると思うのですが。。。
ry188472

2021/10/06 00:30

たしかに表示専用ならDataGridでなくListViewでよかったかもしれません。 >次の質問と関係あるんですよね? この質問は次のとは関係ありません。独立した質問です。 回答頂いている内容は確認ずみでした。BAつけるのを忘れていてすみません。
guest

回答1

0

ベストアンサー

ObserveElementProperty拡張メソッドがあります。

ReactiveProperty v2.1.3をリリースしました - かずきのBlog@hatena

MVVM をリアクティブプログラミングで快適に ReactiveProperty オーバービュー 2020 年版 後編 - Qiita

おそらく効率的な方法があるのでしょうがよくわからなかったので、何か変更があったら全件探索です^^;

xml

1<Window 2 x:Class="Questions362682.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450"> 7 <DockPanel> 8 <DockPanel DockPanel.Dock="Top"> 9 <Button Command="{Binding AddCommand}" Content="Add" /> 10 <TextBlock Text="{Binding IsLargeLength.Value}" /> 11 </DockPanel> 12 <ItemsControl ItemsSource="{Binding Items}"> 13 <ItemsControl.ItemTemplate> 14 <DataTemplate> 15 <DockPanel> 16 <Button 17 Command="{Binding DataContext.DellCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=ItemsControl}}" 18 CommandParameter="{Binding}" 19 Content="Del" /> 20 <TextBox Text="{Binding Id, UpdateSourceTrigger=PropertyChanged}" /> 21 </DockPanel> 22 </DataTemplate> 23 </ItemsControl.ItemTemplate> 24 </ItemsControl> 25 </DockPanel> 26</Window>

cs

1using Prism.Commands; 2using Prism.Mvvm; 3using Reactive.Bindings; 4using Reactive.Bindings.Extensions; 5using System.Collections.ObjectModel; 6using System.Linq; 7using System.Reactive.Linq; 8using System.Windows; 9 10namespace Questions362682 11{ 12 public class MyData : BindableBase 13 { 14 public string Id { get => _id; set => SetProperty(ref _id, value); } 15 private string _id; 16 } 17 18 public class MyDataUserViewModel 19 { 20 public ObservableCollection<MyData> Items { get; } 21 public ReadOnlyReactiveProperty<bool> IsLargeLength { get; } 22 23 public DelegateCommand AddCommand { get; } 24 public DelegateCommand<MyData> DellCommand { get; } 25 26 private int i; 27 28 public MyDataUserViewModel() 29 { 30 Items = new(Enumerable.Range(1, 10).Select(_ => new MyData { Id = $"{i++}", })); 31 32 AddCommand = new(() => Items.Add(new() { Id = $"{i++}", })); 33 DellCommand = new(x => Items.Remove(x)); 34 35 var a = Items.ObserveElementProperty(x => x.Id) 36 .Select(_ => Items.Any(x => x.Id.Length >= 2)); 37 var b = Items.CollectionChangedAsObservable() 38 .Select(_ => Items.Any(x => x.Id.Length >= 2)); 39 IsLargeLength = a.Merge(b).ToReadOnlyReactiveProperty(); 40 } 41 } 42 43 public partial class MainWindow : Window 44 { 45 public MainWindow() 46 { 47 InitializeComponent(); 48 DataContext = new MyDataUserViewModel(); 49 } 50 } 51}

IFilteredReadOnlyObservableCollectionとかも使えるかな?と思ったんのですが、Countを発砲してくれませんでした。。。

投稿2021/10/04 21:59

編集2023/07/29 06:57
TN8001

総合スコア9326

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問