ããŒã1ïŒReactiveUIã®æŠèŠïŒViewModelã®ããããã£ããã³ãã³ã°ãã
åã®èšäºã§ãViewModelã®ããããã£ãšãReactiveUIã䜿çšããŠãããã䜿çšããŠã§ããããšã«ã€ããŠèª¬æããŸããã ããããã£éã®äŸåé¢ä¿ãæŽçãããã¥ãŒã¢ãã«ã®1ãæã«ãããããã£éã®äŸåé¢ä¿ãå«ãŸããŠããæ å ±ãåéããŸããã
ä»åã¯ãããããã£ã«ã€ããŠããå°ã話ããŠãããã³ã¬ã¯ã·ã§ã³ã«ç§»ããŸãããã éåžžã®ã³ã¬ã¯ã·ã§ã³ã«ã¯ã©ããªåé¡ãããã®ãââããªãå€æŽãéç¥ããŠæ°ããã³ã¬ã¯ã·ã§ã³ãäœæããå¿ èŠããã£ãã®ããç解ããŠã¿ãŸãããã ãããŠããã¡ããããããã䜿çšããŠã¿ãŠãã ããã
ããããã£ã«é¢ããããã€ãã®èšè
ã¡ã€ã³ãããã¯ã«ç§»ãåã«ãããããã£ã«ã€ããŠããã€ã説æããŸãã ååã次ã®æ§æã«å°éããŸããã
private string _firstName; public string FirstName { get { return _firstName; } set { this.RaiseAndSetIfChanged(ref _firstName, value); } }
åããããã£ã«6è¡ã®ã³ãŒããè²»ããããšã¯ãç¹ã«ãã®ãããªããããã£ãå€ããå®è£ ãåžžã«åãå Žåã¯ãããªãç¡é§ã§ãã CïŒã§ã¯ããã®åé¡ã解決ããããã«ãèªåããããã£ãäžåºŠã«è¿œå ãããããç°¡åã«ç掻ã§ããããã«ãªããŸããã ç§ãã¡ã®ã±ãŒã¹ã§ã¯äœãã§ããŸããïŒ
ã³ã¡ã³ãã§ã¯ã FodyãèšåãããŸãã-ãããžã§ã¯ãã®ãã«ãåŸã«ILã³ãŒããå€æŽã§ããããŒã«ã§ãã ããšãã°ãå€æŽéç¥ãèªåããããã£ã®å®è£ ã«è¿œå ããŸãã ãŸããReactiveUIã«ã¯ã察å¿ããæ¡åŒµæ©èœã§ããReactiveUI.FodyããããŸãã 䜿ã£ãŠã¿ããã ã¡ãªã¿ã«ãåŸæ¥ã®å®è£ ã®æ¡åŒµæ©èœã§ããPropertyChangedããããŸããã RaiseAndSetIfChangedïŒïŒãåŒã³åºãå¿ èŠããããããç§ãã¡ã«ã¯é©ããŠããŸããã
NuGetïŒ> Install-Package ReactiveUI.Fodyããã€ã³ã¹ããŒã«ããŸã
FodyWeavers.xmlããããžã§ã¯ãã«è¡šç€ºãããŸãã ã€ã³ã¹ããŒã«æžã¿ã®æ¡åŒµæ©èœãè¿œå ããŸãã
<?xml version="1.0" encoding="utf-8" ?> <Weavers> <ReactiveUI /> </Weavers>
ãããŠãããããã£ãå€æŽããŸãã
[Reactive] public string FirstName { get; set; }
ãã®ããŒã«ã䜿çšãããšãObservableAsPropertyHelper <>ã«åºã¥ããŠFullNameããããã£ãå®è£ ããããšãã§ããŸãã ãã®æ¹æ³ã¯GitHubã®ããã¥ã¡ã³ãã§èª¬æãããŠããŸãããããã§ã¯çç¥ããŸãã 2è¡ã¯å®å šã«åãå ¥ãããããªãã·ã§ã³ã ãšæããŸããRePropertyUI.Fodyããã®ããããã£ãæ£ããå®è£ ã§ããããã«ããToPropertyïŒïŒã®ä»£ããã«ããµãŒãããŒãã£ã®ã¡ãœããã䜿çšããããããŸããã
äœãå£ããŠããªãããšã確èªããŸãã ã©ããã£ãŠïŒ åäœãã¹ãã§ç¢ºèªããŸãã ReactiveUIã¯ãããã«å奜çã§ããã MVVMãã¬ãŒã ã¯ãŒã¯<...>ããšã¬ã¬ã³ãã§ãã¹ãå¯èœãªãŠãŒã¶ãŒã€ã³ã¿ãŒãã§ãŒã¹ãäœæããã®ã¯ãäœã®ããã§ããããŸãã.... ã€ãã³ãã®ããªã¬ãŒã確èªããã«ã¯ãæåã§ãµã€ã³ã¢ããããããªã¬ãŒããããšãã«ããŒã¿ãä¿åããŠããåŠçããå¿ èŠã¯ãããŸããã
Observable.FromEventPatternïŒïŒã¯ãã€ãã³ãããªã¬ãŒããã¹ãŠã®å¿ èŠãªæ å ±ãšãšãã«IObservable <>ã«å€æããã®ã«åœ¹ç«ã¡ãŸãã IObservable <>ãã€ãã³ãã®ãªã¹ãã«å€æããæ£ç¢ºæ§ã確èªããã«ã¯ãæ¡åŒµã¡ãœãã.CreateCollectionïŒïŒã䜿çšãããšäŸ¿å©ã§ãã 圌ã¯ããœãŒã¹ãOnCompleteïŒïŒãåŒã³åºãããDisposeïŒïŒãåŒã³åºããŸã§ãIObservable <>ãçµç±ããèŠçŽ ãè¿œå ãããã³ã¬ã¯ã·ã§ã³ãäœæããŸãããã®å Žåãããªã¬ãŒãããã€ãã³ãã«é¢ããæ å ±ãè¿œå ãããŸãã
ã³ã¬ã¯ã·ã§ã³ã¯ããã«è¿ãããåŸã§éåæçã«èŠçŽ ãè¿œå ãããããšã«æ³šæããŠãã ããã ãã®åäœã¯ãããšãã°.ToListïŒïŒãšã¯ç°ãªããŸãã.ToListïŒïŒã¯å¶åŸ¡ãè¿ããªããããã³ã¬ã¯ã·ã§ã³èªäœã¯OnCompleteïŒïŒã«è¿ãããŸããOnCompleteïŒïŒã¯ãéåžžã®ã€ãã³ããµãã¹ã¯ãªãã·ã§ã³ã®å Žåã¯æ°žé ã«åŸ æ©ããŸãã
[Test] public void FirstName_WhenChanged_RaisesPropertyChangedEventForFirstNameAndFullNameProperties() { var vm = new PersonViewModel("FirstName", "LastName"); var evendObservable = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>( a => vm.PropertyChanged += a, a => vm.PropertyChanged -= a); var raisedEvents = evendObservable.CreateCollection(); using (raisedEvents) { vm.FirstName = "NewFirstName"; } Assert.That(vm.FullName, Is.EqualTo("NewFirstName LastName")); Assert.That(raisedEvents, Has.Count.EqualTo(2)); Assert.That(raisedEvents[0].Sender, Is.SameAs(vm)); Assert.That(raisedEvents[0].EventArgs.PropertyName, Is.EqualTo(nameof(PersonViewModel.FirstName))); Assert.That(raisedEvents[1].Sender, Is.SameAs(vm)); Assert.That(raisedEvents[1].EventArgs.PropertyName, Is.EqualTo(nameof(PersonViewModel.FullName))); }
ãã¹ãã¹ã¯ãªããèªäœïŒããããã£ã«æ°ããå€ãèšå®ããïŒã¯usingã®å éšã§å®è¡ããããã®åŸã§ãã§ãã¯ãè¡ãããŸãã ããã¯ããã§ãã¯äžã«äžéšã®ã€ãã³ãã誀ã£ãŠæ©èœãããã³ã¬ã¯ã·ã§ã³ãæãªãããªãããã«ããããã«å¿ èŠã§ãã ãã¡ãããããã¯ãã°ãã°å¿ èŠã§ã¯ãããŸããããæã«ã¯éèŠã«ãªãå ŽåããããŸãã
IObservable <> Changedãåããã®ãè¿ãããšã確èªããŸãããã
[Test] public void FirstName_WhenChanged_PushesToPropertyChangedObservableForFirstNameAndFullNameProperties() { var vm = new PersonViewModel("FirstName", "LastName"); var notifications = vm.Changed.CreateCollection(); using (notifications) { vm.FirstName = "NewFirstName"; } Assert.That(vm.FullName, Is.EqualTo("NewFirstName LastName")); Assert.That(notifications, Has.Count.EqualTo(2)); Assert.That(notifications[0].Sender, Is.SameAs(vm)); Assert.That(notifications[0].PropertyName, Is.EqualTo(nameof(PersonViewModel.FirstName))); Assert.That(notifications[1].Sender, Is.SameAs(vm)); Assert.That(notifications[1].PropertyName, Is.EqualTo(nameof(PersonViewModel.FullName))); }
ãããŠ...ãã¹ãã¯èœã¡ãŸããã ããããããããã£ã®å€æŽã«é¢ããæ å ±ã®ãœãŒã¹ãå€æŽããŸããïŒ ãã¹ãã倱æããçç±ãç解ããŠã¿ãŸãããã
vm.Changed.Subscribe(n => Console.WriteLine(n.PropertyName)); vm.FirstName = "OMG";
ãããŠãæã ã¯åŸãïŒ
æ°å
å
è¡ãã ããã¯ãã¬ãŒã ã¯ãŒã¯ã®ãã°ã§ã¯ãªããå®è£ ã®è©³çŽ°ã®ããã§ãã ããã¯ç解ã§ããŸããäž¡æ¹ã®ããããã£ã¯ãã§ã«å€æŽãããŠãããéç¥ã®é åºã¯éèŠã§ã¯ãããŸããã äžæ¹ã§ãã€ãã³ãã®é åºãšäžèŽãããæåŸ ãæºãããŠããªããããæ··ä¹±ããå¯èœæ§ããããŸãã ãã¡ãããéç¥ã®é åºã«åºã¥ããŠã¢ããªã±ãŒã·ã§ã³ããžãã¯ãæ§ç¯ããããšã¯æããã«æªãèãã§ãã ããããããšãã°ãã¢ããªã±ãŒã·ã§ã³ãã°ãèªã¿åããšãäŸåé¢ä¿ããããã£ãäŸåé¢ä¿ã®å€æŽåã«å€æŽã«ã€ããŠéç¥ããŠããããšãããããŸãã ãããã£ãŠããã®æ©èœãå¿ããªãã§ãã ããã
ãã®ãããReactiveUI.Fodyãé©åã«åäœããã³ãŒãã®éãå€§å¹ ã«åæžããããã«ããŸããã 次ã«ããã䜿çšããŸãã
ããã§ã¯ãã³ã¬ã¯ã·ã§ã³ã«ç§»ããŸããã
INotifyPropertyChangedã€ã³ã¿ãŒãã§ã€ã¹ã¯ãæ¢ç¥ã®ããã«ããã¥ãŒã¢ãã«ã®ããããã£ãå€æŽããå Žåã«äœ¿çšãããŸããããšãã°ãäœããå€æŽãããã€ã³ã¿ãŒãã§ã€ã¹ãåæç»ããå¿ èŠãããããšãèŠèŠèŠçŽ ã«éç¥ããããã«äœ¿çšãããŸãã ãããããã¥ãŒã¢ãã«ã«å€ãã®èŠçŽ ã®ã³ã¬ã¯ã·ã§ã³ïŒãã¥ãŒã¹ãã£ãŒããªã©ïŒããããæ¢ã«è¡šç€ºãããŠãããã®ã«æ°ãããšã³ããªãè¿œå ããå¿ èŠãããå Žåã¯ã©ãããã°ããã§ããããã ã³ã¬ã¯ã·ã§ã³ãååšããããããã£ãå€æŽãããããšãéç¥ããŸããïŒ å¯èœã§ãããã€ã³ã¿ãŒãã§ã€ã¹å ã®ãªã¹ãå šäœãåé 眮ãããããšã«ãªããç¹ã«ã¢ãã€ã«ããã€ã¹ã®å Žåã¯ãæäœãé ããªãå¯èœæ§ããããŸãã ããããããã¯æ©èœããŸããã ã³ã¬ã¯ã·ã§ã³èªäœãäœããå€æŽãããããšãéç¥ããå¿ èŠããããŸãã 幞ããªããšã«ãçŽ æŽãããã€ã³ã¿ãŒãã§ãŒã¹ããããŸãïŒ
public interface INotifyCollectionChanged { /// <summary>Occurs when the collection changes.</summary> event NotifyCollectionChangedEventHandler CollectionChanged; }
ã³ã¬ã¯ã·ã§ã³ããããå®è£ ããå Žåãè¿œå /åé€/眮æãªã©ã®å Žå CollectionChangedã«ãã£ãŠããªã¬ãŒãããã€ãã³ãã ãŸãããã¥ãŒã¹ãªã¹ããå床äœæãçŽããŠã¬ã³ãŒãã®ã³ã¬ã¯ã·ã§ã³å šäœã確èªããå¿ èŠã¯ãããŸãããã€ãã³ããéããŠè¿œå ãããæ°ããèŠçŽ ãè¿œå ããã ãã§ãã .NETã«ã¯ãããå®è£ ããã³ã¬ã¯ã·ã§ã³ããããŸãããReactiveUIã«ã€ããŠè©±ããŠããŸãã äœãå ¥ã£ãŠããã®ïŒ
ã€ã³ã¿ãŒãã§ã€ã¹ã®ã»ããå šäœïŒIReactiveList <T>ãIReadOnlyReactiveList <T>ãIReadOnlyReactiveCollection <T>ãIReactiveCollection <T>ãIReactiveNotifyCollectionChanged <T>ãIReactiveNotifyCollectionItemChanged <T>ã ããã§ã¯ããããã®èª¬æã¯ããŸããããããããäœã§ããããšããååããæ確ã«ãã¹ãã ãšæããŸãã
ããããå®è£ ãããã«è©³ããèŠãŠã¿ãŸãããã äŒãïŒReactiveList <T>ã 圌ã¯ããããã¹ãŠãå®è£ ããŠããŸãã ã³ã¬ã¯ã·ã§ã³ã®å€æŽã远跡ããããšã«èå³ãããã®ã§ããã®ã¯ã©ã¹ã®å¯Ÿå¿ããããããã£ãèŠãŠã¿ãŸãããã
ããªãããããïŒ èŠçŽ ã®è¿œå ãåé€ã移åãèŠçŽ ã®æ°ãã³ã¬ã¯ã·ã§ã³ã®ç©ºããªã»ããã®å¿ èŠæ§ãç£èŠããŸãã ããããã¹ãŠè©³çŽ°ã«æ€èšããŠãã ããã ãã¡ãããINotifyCollectionChangedãINotifyPropertyChangedãããã³ãããã®ãã¢ã«ãªã£ã* Changindããã®ã€ãã³ããå®è£ ãããŸããããããã«ã€ããŠã¯èª¬æããŸããããããã¯ãå³ã«ç€ºãããŠããã芳枬å¯èœãªãããããã£ãšäžŠè¡ããŠåäœããããã«ã¯ãŠããŒã¯ãªãã®ã¯ãããŸããã
æå§ãã«ãç°¡åãªäŸã éç¥ã®ããã€ãã®ãœãŒã¹ããµãã¹ã¯ã©ã€ãããã³ã¬ã¯ã·ã§ã³ãå°ãæäœããŸãã
var list = new ReactiveList<string>(); list.BeforeItemsAdded.Subscribe(e => Console.WriteLine($"Before added: {e}")); list.ItemsAdded.Subscribe(e => Console.WriteLine($"Added: {e}")); list.BeforeItemsRemoved.Subscribe(e => Console.WriteLine($"Before removed: {e}")); list.ItemsRemoved.Subscribe(e => Console.WriteLine($"Removed: {e}")); list.CountChanging.Subscribe(e => Console.WriteLine($"Count changing: {e}")); list.CountChanged.Subscribe(e => Console.WriteLine($"Count changed: {e}")); list.IsEmptyChanged.Subscribe(e => Console.WriteLine($"IsEmpty changed: {e}")); Console.WriteLine("# Add 'first'"); list.Add("first"); Console.WriteLine("\n# Add 'second'"); list.Add("second"); Console.WriteLine("\n# Remove 'first'"); list.Remove("first");
çµæãåŸãããŸãã
ïŒãæåããè¿œå
ã«ãŠã³ãå€æŽïŒ0
è¿œå åïŒæå
å€æŽãããã«ãŠã³ãïŒ1
å€æŽãããIsEmptyïŒFalse
è¿œå ïŒæå
ïŒãç§ããè¿œå
ã«ãŠã³ãå€æŽïŒ1
è¿œå åïŒ2çªç®
å€æŽãããã«ãŠã³ãïŒ2
è¿œå ïŒ2çªç®
ïŒãæåããåé€
ã«ãŠã³ãå€æŽïŒ2
åé€ããåïŒæå
å€æŽãããã«ãŠã³ãïŒ1
åé€æžã¿ïŒæå
è¿œå ãŸãã¯åé€ããããã®ãèŠçŽ ã®æ°ã®å€æŽãã³ã¬ã¯ã·ã§ã³ã®ç©ºã®å åãéç¥ãããŸãã
ããã«ïŒ
-ItemsAdded / ItemsRemoved / BeforeItemsAdded / BeforeItemsRemovedã¯ãè¿œå ãŸãã¯åé€ãããã¢ã€ãã èªäœãè¿ããŸã
-CountChanging / CountChangedã¯ãå€æŽååŸã®èŠçŽ ã®æ°ãè¿ããŸã
-IsEmptyChangedã¯ãã³ã¬ã¯ã·ã§ã³ã®ç©ºã®å±æ§ã®æ°ããå€ãè¿ããŸã
埮åŠãªç¹ã1ã€ãããŸã
ãããŸã§ã®ãšããããã¹ãŠãäºæž¬å¯èœã§ãã ããã§ãã³ã¬ã¯ã·ã§ã³å ã®ã¬ã³ãŒãã®æ°ãã«ãŠã³ãããã®ã¯ãè¿œå ãšåé€ã®éç¥ã«åºã¥ããŠã®ã¿ã§ãããšæ³åããŠãã ããã äœããã£ãšç°¡åã ãããïŒ
var count = 0; var list = new ReactiveList<int>(); list.ItemsAdded.Subscribe(e => count++); list.ItemsRemoved.Subscribe(e => count--); for (int i = 0; i < 100; i++) { list.Add(i); } for (int i = 0; i < 100; i+=2) { list.Remove(i); } Assert.That(count, Is.EqualTo(list.Count));
ãã¹ãã¯æåããŸããã ã³ã¬ã¯ã·ã§ã³ãåããååãå€æŽããäžåºŠã«å€ãã®èŠçŽ ãè¿œå ããŸãã
list.AddRange(Enumerable.Range(0, 10)); list.RemoveAll(Enumerable.Range(0, 5).Select(i => i * 2));
æåããŸããã ãã£ããã¯ãªãããã§ãã ã¡ãã£ãšåŸ ã£ãŠâŠ
list.AddRange(Enumerable.Range(0, 100)); list.RemoveAll(Enumerable.Range(0, 50).Select(i => i * 2));
ããïŒ ãã¹ãã¯å€±æããcount == 0ã«ãªããŸãããäœããèæ ®ããŠããªãããã§ãã æ£ããããŸãããã
åé¡ã¯ãReactiveList <T>ã¯èŠããã»ã©ããªããã£ãã«å®è£ ãããŠããªãããšã§ãã ã³ã¬ã¯ã·ã§ã³ãå€§å¹ ã«å€æŽããããšãéç¥ããªãã«ãããã¹ãŠã®å€æŽãè¡ããéç¥ããªã³ã«æ»ãããªã»ããä¿¡å·ãéä¿¡ããŸãã
list.ShouldReset.Subscribe(_ => Console.WriteLine("ShouldReset"));
ãªããããè¡ãããã®ã§ããïŒ ã³ã¬ã¯ã·ã§ã³ãå€§å¹ ã«å€æŽãããå ŽåããããŸããããšãã°ã100åã®èŠçŽ ã空ã®ã³ã¬ã¯ã·ã§ã³ã«è¿œå ãããããèŠçŽ ã®ååã倧ããªã³ã¬ã¯ã·ã§ã³ããåé€ãããããå®å šã«åé€ããããããŸãã ãã®å Žåãå°ããªå€æŽãã¹ãŠã«å¿çããæå³ã¯ãããŸãããäžé£ã®å€æŽã®çµäºãåŸ ã£ãŠãã³ã¬ã¯ã·ã§ã³ãå®å šã«æ°ãããã®ããã«åå¿ãããããã³ã¹ããé«ããªããŸãã
æåŸã®äŸã§ã¯ããããèµ·ãããŸãã ShouldResetã®ã¿ã€ãã¯IObservable <Unit>ã§ãã ãŠãããã¯ããªããžã§ã¯ãã®åœ¢åŒã§ã®ã¿ãæ¬è³ªçã«ç¡å¹ã§ãã ã€ãã³ãã®ãµãã¹ã¯ã©ã€ããŒã«éç¥ããå¿ èŠãããç¶æ³ã§äœ¿çšãããçºçããããšãéèŠã§ããã ãã§ãè¿œå ããŒã¿ãéä¿¡ããå¿ èŠã¯ãããŸããã ã¡ããã©ç§ãã¡ã®å Žåã ãµãã¹ã¯ã©ã€ãããå Žåãæ¿å ¥ããã³åé€æäœã®åŸã«ãªã»ããä¿¡å·ãåä¿¡ããããšãããããŸãã ãããã£ãŠãã«ãŠã³ã¿ãŒãæ£ããæŽæ°ããã«ã¯ãäŸãå°ãå€æŽããå¿ èŠããããŸãã
list.ItemsAdded.Subscribe(e => count++); list.ItemsRemoved.Subscribe(e => count--); list.ShouldReset.Subscribe(_ => count = list.Count);
ããã§ãã¹ãã«åæ Œãããã¹ãŠæ£åžžã«ãªããŸããã ããã€ãã®éç¥ãæ¥ãŠãããã®ç¶æ³ãåŠçããªããããããªãããšãå¿ããªãã§ãã ããã ãããŠããã¡ãããã³ã¬ã¯ã·ã§ã³ã倧ããå€åãããããªç¶æ³ããã¹ãããããšãå¿ããªãã§ãã ããã
éç¥æå¶ã«ãŒã«ã®å€æŽ
ã³ã¬ã¯ã·ã§ã³ã«å€§ããªå€åããããšããªã»ããä¿¡å·ãçºçããããšãããããŸããã ãã®ããã»ã¹ã¯ã©ã®ããã«å¶åŸ¡ã§ããŸããïŒ
ReactiveList <T>ã³ã³ã¹ãã©ã¯ã¿ãŒã«ã¯ãdouble resetChangeThreshold = 0.3ãšãããªãã·ã§ã³ã®åŒæ°ã1ã€ãããŸãã ãªã¹ãã®äœæåŸãResetChangeThresholdããããã£ã䜿çšããŠãªã¹ããå€æŽã§ããŸãã ã©ã®ããã«äœ¿çšãããŸããïŒ è¿œå /åé€ãããã¢ã€ãã ã®æ°ãã³ã¬ã¯ã·ã§ã³èªäœã®ã¢ã€ãã ã®æ°ã§å²ã£ãçµæããã®å€ããã倧ãããè¿œå /åé€ãããã¢ã€ãã ã®æ°ãå³å¯ã«10ãã倧ããå Žåãå€æŽã®éç¥ã¯æå¶ãããŸããå°æ¥å€æŽãããŸããã
ãã®äŸã§ã¯ã 100/ 0> 0.3ããã³50/100> 0.3ãªã®ã§ãéç¥ã¯äž¡æ¹ã®æéã§æå¶ãããŸããã åœç¶ãResetChangeThresholdãå€æŽããŠãã³ã¬ã¯ã·ã§ã³ãç¹å®ã®äœ¿çšå Žæã«çœ®ãæããããšãã§ããŸãã
éç¥ãã©ã®ããã«æå¶ããã®ã§ããïŒ
ã«ãŠã³ã¿ãŒã䜿çšããæåã®äŸã§ã¯ã次ã®ã³ãŒããèŠãŸããã
for (int i = 0; i < 100; i++) { list.Add(i); }
ããã§ã¯ãã¢ã€ãã ã1ã€ãã€è¿œå ããããããå€æŽéç¥ã¯åžžã«éä¿¡ãããŸãã ããããç§ãã¡ã¯å€ãã®èŠçŽ ãè¿œå ããŠããããã°ããã®ééç¥ãæå¶ããããšèããŠããŸãã ã©ããã£ãŠïŒ SuppressChangeNotificationsïŒïŒã䜿çšããŸãã usingå ã®ãã¹ãŠãå€æŽéç¥ãããªã¬ãŒããŸããïŒ
using (list.SuppressChangeNotifications()) { for (int i = 0; i < 100; i++) { list.Add(i); } }
ã³ã¬ã¯ã·ã§ã³èªäœã®èŠçŽ ã®å€æŽã«ã€ããŠã¯ã©ãã§ããïŒ
ReactiveList <T>ã«ã¯ãItemChangedããã³ItemChangingãšããéç¥ã®ãœãŒã¹ããããŸã-èŠçŽ èªäœãžã®å€æŽã ãããã䜿çšããŠã¿ãŸãããïŒ
var list = new ReactiveList<PersonViewModel>(); list.ItemChanged.Subscribe(e => Console.WriteLine(e.PropertyName)); var vm = new PersonViewModel("Name", "Surname"); list.Add(vm); vm.FirstName = "NewName";
äœãèµ·ãããŸããã§ããã ã ãŸãããŠãããReactiveListã¯èŠçŽ ã®å€æŽãå®éã«ç£èŠããŠããŸãããïŒ ã¯ãããã ãããã©ã«ãã§ã®ã¿ã 圌ãèŠçŽ å ã®å€æŽã远跡ããã«ã¯ããã®æ©èœãæå¹ã«ããã ãã§ãã
var list = new ReactiveList<PersonViewModel>() { ChangeTrackingEnabled = true };
ããã§ãã¹ãŠãæ©èœããŸãïŒ
æ°å
å
ãŸããäœæ¥äžã«ãªã³ãšãªããåãæ¿ããããšãã§ããŸãã ãªãã«ãããšãã¢ã€ãã ã«å¯Ÿããæ¢åã®å éšãµãã¹ã¯ãªãã·ã§ã³ãåé€ããããªã³ã«ãããšãã¢ã€ãã ãäœæãããŸãã åœç¶ããµãã¹ã¯ãªãã·ã§ã³ã¢ã€ãã ã®è¿œå /åé€æã«ãåé€ããã³è¿œå ãããŸãã
ç¶æ¿ãããã³ã¬ã¯ã·ã§ã³
æ¢åã®ã³ã¬ã¯ã·ã§ã³ããèŠçŽ ã®äžéšã®ã¿ãéžæãããã䞊ã¹æ¿ããããå€æãããããå¿ èŠãããå Žåãã©ã®ãããã®é »åºŠã§ç¶æ³ãçºçããŸããïŒ å ã®ã³ã¬ã¯ã·ã§ã³ãå€æŽãããšãã¯ãäŸåããã³ã¬ã¯ã·ã§ã³ãå€æŽããŸãã ãã®ãããªç¶æ³ã¯çãããªããReactiveUIã«ã¯ãããç°¡åã«è¡ããããŒã«ããããŸãã 圌ã®ååã¯DerivedCollectionã§ãã ãããã¯ReactiveListããç¶æ¿ããããããæ©èœã¯åãã§ããããã®ãããªã³ã¬ã¯ã·ã§ã³ãå€æŽããããšãããšäŸå€ãã¹ããŒãããŸãã ã³ã¬ã¯ã·ã§ã³ã¯ããã®ããŒã¹ã³ã¬ã¯ã·ã§ã³ãå€æŽããããšãã«ã®ã¿å€æŽã§ããŸãã
å€æŽã®éç¥ãå床æ€èšããããšã¯ãããŸããããã¹ãŠã以åãšåãã§ãã åºæ¬ã³ã¬ã¯ã·ã§ã³ã«é©çšã§ããå€æãèŠãŠã¿ãŸãããã
var list = new ReactiveList<int>(); list.AddRange(Enumerable.Range(1, 5)); var derived = list.CreateDerivedCollection( selector: i => i*2, filter: i => i % 2 != 0, orderer:(a, b) => b.CompareTo(a)); Console.WriteLine(string.Join(", ", list)); Console.WriteLine(string.Join(", ", derived)); list.AddRange(Enumerable.Range(2, 3)); Console.WriteLine(string.Join(", ", list)); Console.WriteLine(string.Join(", ", derived));
å€ãå€æããå ã®èŠçŽ ããã£ã«ã¿ãŒåŠçããŠããïŒå€æåã«ïŒïŒãå€æãããèŠçŽ ã«ã³ã³ãã¬ãŒã¿ãŒãæž¡ãããšãã§ããããšãããããŸãã ããã«ãã»ã¬ã¯ã¿ãŒã®ã¿ãå¿ èŠã§ãæ®ãã¯ãªãã·ã§ã³ã§ãã
INotifyCollectionChangedã ãã§ãªããIEnumerable <>ãããŒã¹ã³ã¬ã¯ã·ã§ã³ãšããŠäœ¿çšã§ããããã«ããã¡ãœãããªãŒããŒããŒãããããŸãã ãããããã®åŸãç¶æ¿ãããã³ã¬ã¯ã·ã§ã³ã«ãªã»ããä¿¡å·ãååŸããæ¹æ³ãæäŸããå¿ èŠããããŸãã
ããã§ãç¶æ¿ãããã³ã¬ã¯ã·ã§ã³ã¯å ã®ã³ã¬ã¯ã·ã§ã³ããå¥æ°ã®èŠçŽ ãååŸãããã®å€ã2åã«ããŠã倧ãããã®ããå°ãããã®ã«äžŠã¹æ¿ããŸãã ã³ã³ãœãŒã«ã«ã¯æ¬¡ã®ããã«ãªããŸãã
1ã2ã3ã4ã5
10ã6ã2
1ã2ã3ã4ã5ã2ã3ã4
10ã6ã6ã2
ã楜ãã¿ã«
ä»åã¯ãæåŸã®éšåã§èª¬æãããŠããªãããããã£ã®æäœã®è©³çŽ°ã«ã€ããŠèª¬æããŸããã 圌ãã¯ãããããã£ã®å®è£ ã1è¡ãå ããããã«ããå€æŽã«é¢ããéç¥ã®é åºãä¿¡é Œã§ããªãããšã確èªããŸããã äž»ãªããŒãã¯ã³ã¬ã¯ã·ã§ã³ã§ããã ReactiveListãå€æŽããããšãã«ReactiveListããååŸã§ããéç¥ãææ¡ããŸããã éç¥ãèªåçã«æå¶ãããçç±ãšæ¡ä»¶ãããã³èªåã®æã§éç¥ãæå¶ããæ¹æ³ãèŠã€ããŸããã æåŸã«ãç¶æ¿ãããã³ã¬ã¯ã·ã§ã³ã䜿çšããŠãå€æŽã«å¿ããŠããŒã¹ã³ã¬ã¯ã·ã§ã³å ã®ããŒã¿ããã£ã«ã¿ãŒåŠçãå€æãããã³äžŠã¹æ¿ãã§ããããšã確èªããŸããã
次ã®ããŒãã§ã¯ãããŒã ã«ã€ããŠè©±ãããã¥ãŒã¢ãã«ã®ãã¹ãã®åé¡ãæ€èšããŸãã ããã«é¢é£ããåé¡ãšãã®è§£æ±ºæ¹æ³ã確èªããŸãã 次ã«ãView + ViewModelãã³ãã«é²ã¿ãæ¢ã«èª¬æããããŒã«ã䜿çšããå°ããªGUIã¢ããªã±ãŒã·ã§ã³ãå®è£ ããŠã¿ãŸãããã
ããããïŒ