という問題が出されました。 うんうんと頭をひねった結果こうなりました…ちょっと全ループしてるのがダサい。ReactiveProperty 2.x前提です。
まず、表示するデータ。
using Reactive.Bindings; namespace DupItemColorApp { publicclass PersonViewModel { public ReactiveProperty<string> Name { get; private set; } public ReactiveProperty<int> Age { get; private set; } public ReactiveProperty<string> BackgroundColor { get; private set; } public PersonViewModel() { this.Name = new ReactiveProperty<string>(); this.Age = new ReactiveProperty<int>(); this.BackgroundColor = new ReactiveProperty<string>("White"); } publicstatic PersonViewModel Create(string name, int age) { var result = new PersonViewModel(); result.Name.Value = name; result.Age.Value = age; return result; } } }
こいつのBackgroundColorをいじってDataGridのRowの色を変えるつもりです。
プロパティの変更と要素の変更時に全走査!ダサい…もっといい方法募集中。一応連続での値の変更なんかに対応するためにThrottle入れて緩和してる。
using Reactive.Bindings; using Reactive.Bindings.Extensions; using System; using System.Collections.ObjectModel; using System.Diagnostics; using System.Linq; using System.Reactive.Linq; namespace DupItemColorApp { publicclass MainWindowViewModel { privatestaticreadonlystring[] Names = new[] { "hoge", "fuga", "piyo", "foo", "bar", "bazz", "fizz", }; privatereadonly ObservableCollection<PersonViewModel> people = new ObservableCollection<PersonViewModel>(); public ReadOnlyReactiveCollection<PersonViewModel> People { get; private set; } public ReactiveCommand AddCommand { get; private set; } public MainWindowViewModel() { this.People = this.people.ToReadOnlyReactiveCollection(); this.People.ObserveElementObservableProperty(x => x.Name) .Throttle(TimeSpan.FromMilliseconds(500)) .Subscribe(x => { Console.WriteLine("Name changed."); foreach (var item inthis.People.ToArray()) { item.BackgroundColor.Value = "White"; } this.ChangeBackgroundColor(); }); this.People.CollectionChangedAsObservable() .Throttle(TimeSpan.FromMilliseconds(500)) .Subscribe(_ => this.ChangeBackgroundColor()); this.AddCommand = new ReactiveCommand(); this.AddCommand.Subscribe(_ => { for (int i = 0; i < 1000; i++) { var name = Names.OrderBy(x => Guid.NewGuid()).First(); this.people.Add(PersonViewModel.Create(name, 0)); } }); } privatevoid ChangeBackgroundColor() { Debug.WriteLine("ChangeBackgroundColor called."); foreach (var item inthis.People.ToArray().GroupBy(x => x.Name.Value).Where(x => x.Count() > 1).SelectMany(x => x)) { item.BackgroundColor.Value = "Red"; } } } }
んで、XAML。これはバインドしてるだけ。
<Window x:Class="DupItemColorApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:DupItemColorApp"mc:Ignorable="d"Title="MainWindow"Height="350"Width="525"><Window.DataContext><local:MainWindowViewModel /></Window.DataContext><Grid><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition /></Grid.RowDefinitions><Menu><MenuItem Header="Add"Command="{Binding AddCommand}" /></Menu><DataGrid Grid.Row="1"ItemsSource="{Binding People}"AutoGenerateColumns="False"UseLayoutRounding="True"><DataGrid.RowStyle><Style TargetType="DataGridRow"><Setter Property="Background"Value="{Binding BackgroundColor.Value}" /></Style></DataGrid.RowStyle><DataGrid.Columns><DataGridTextColumn Header="Name"Binding="{Binding Name.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /><DataGridTextColumn Header="Age"Binding="{Binding Age.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /></DataGrid.Columns></DataGrid></Grid></Window>