ReactiveUI: Rx + MVVM
-
Upload
stas-shusha -
Category
Engineering
-
view
2.447 -
download
24
Transcript of ReactiveUI: Rx + MVVM
Reactive UIReactive Extensions + MVVM
Rx.NETpublic interface IObservable<out T>{ IDisposable Subscribe(IObserver<T> observer);}
public interface IObserver<in T>{ void OnNext(T value); void OnError(Exception error); void OnCompleted();}
WP8
WinRT
Xamarin.Android
Xamarin.Touch
Xamarin.Mac
WPF
WinForms
Reactive Extensions + MVVMIObservable и LINQ +
INPC, INCCTextBox.TextChanged, ManipulationStartedEventетц.изменения значения BindingICommand вызовы, CanExecuteChangedFrame.Navigated, App.IsResuming етц.тестируемый параллелизм (concurrency)
ReactiveObjectpublic class VM : ReactiveObject { public VM() { this.WhenAnyValue(x => x.Name) .Select(x => x.Split( ' ')[0]) .ToProperty( this, x => x.FirstName); }
public string FirstName {get; private set;}}
Декларативный стильсвойство FirstName это подстрока Name до пробела
свойство BackgroundBrush это свойства Red, Green, Blue, объединенные в объект
Color, трансформированный в SolidColorBrush
Кнопка Login может быть нажата если свойства пароль и подтверждение пароля
непусты и совпадают
Output Propertiesthis.WhenAny(x => x.Red, x => x.Green, x => x.Blue, (r, g, b) => Color.FromRgb(r.Value, g.Value, b.Value)) .Select(color => new SolidColorBrush(color)) .ToProperty(this, x => x.BackgroundBrush);
public SolidColorBrush BackgroundBrush {get; private set;}
Eventsпример AutoComplete сценария
var searchTerms = txt.Events().TextChanged .Select(_ => txt.Text) .Where(term => term.Length > 3) .Throttle(TimeSpan.FromSeconds( 1)) .DistinctUntilChanged();
var searchResults = from term in searchTerms from words in _service.Search(term).TakeUntil(searchTerms) select words;
searchResults.ObserveOnDispatcher() .Subscribe(words => itemsControl.ItemsSource = words)
CommandsCanExecute via IObservable
var commandCanExecute = new Subject<bool>(); var command = new ReactiveCommand(commandCanExecute);
commandCanExecute.OnNext(false); command.CanExecute(null); >>> false
commandCanExecute.OnNext(true); command.CanExecute(null); >>> true</bool>
Async action per Command executeLoadUsersAndAvatars = new ReactiveCommand();
var usersAndAvatarResults = LoadUsersAndAvatars.RegisterAsyncTask(async _ => { var users = await LoadUsers();
foreach(var u in users) { u.Avatar = await LoadAvatar(u.Id); }
return users;});
usersAndAvatarResults.ToProperty(this, x => x.Users, ref users);
Bindings in code-behind
C# более экспрессивен, нежели XAMLthis.OneWayBind(ViewModel, x => x.Name, x => x.Name.Text);this.Bind(ViewModel, x => x.Name, x => x.Name.Text);// Bind the OK command to the buttonthis.BindCommand(ViewModel, x => x.OkCommand, x => x.OkButton);// Bind the OK command to when the user presses a keythis.BindCommand(ViewModel, x => x.OkCommand, x => x.RootView, "KeyUp");
INCC, ReactiveListIObservable => (selector, filter, orderer) => INCCthis.Feeds = feedModels.CreateCollection() .CreateDerivedCollection( CreateViewModel, model => model.LatestPublished > TimeBorder, FreshFirstOrderer);
ISchedulerВ Rx все асинхронные действия происходят с
помощью ISchedulervar initialDate = DateTime.Now;//simulate some cold data before ViewModel creation (and subscription)testPodcastsSubj.OnNext(new TestPodcastItem(1, initialDate.AddDays(1)));testPodcastsSubj.OnNext(new TestPodcastItem(2, initialDate.AddDays(2)));
var model = new FeedViewModel("TestFeed", testPodcasts);
Assert.AreEqual(2, ((TestPodcastItem)model.LastFeedItem).Id);Assert.AreEqual(2, model.Items.Count);
testPodcastsSubj.OnNext(new TestPodcastItem(3, initialDate.AddDays(3)));_virtualScheduler.AdvanceBy(TimeSpan.FromSeconds(1));
Assert.AreEqual(3, ((TestPodcastItem)model.LastFeedItem).Id);
Спасибо за внимание!Сабж: ReactieUI его автор: Паша Betts
и я, Стас Шуша
https://github.com/reactiveui
https://github.com/paulcbettsViber: +375298745697