Комментарии 9
Сам я чисто десктопный code-monkey, но порывался освоить андроид пару раз, в т.ч. Xamarin. Оба раза бросал это дело, потерпев неудачу с hello world (в окне с полем ввода и кнопкой элементы наезжали друг на друга и растащить их не удавалось).
В третий раз попробовать, что ли…
Аналогичная ситуация была, в качестве хобби делал одностраничные програмки на WinForm для автоматизации рутины. В первое время отталкивало отсутствие визуального редактора, для каждого изменения необходимо было заново билдить приложение, что отнимает не мало времени. В прошлом году появилась отличная фича — XAML Hot Reload, позволяющая изменять разметку XAML во время выполнения приложения, что экономит кучу времени.
Начните с самого простого расположения — StackLayout, когда элементы располагаются друг за другом, после попробовать Grid. Для более сложной разметки комбинацию данных слоев.
Если Microsoft не станет продвигать Xamarin ещё активнее, то в ближайшие 10 лет, он просто канет в лету.
Правду же говорят: Xamarin — хорошо подходит для MVP, а не для конечного продукта.
На своём опыте скажу, что Xamarin.Forms + System.Reactive + Мобильное устройство = подтормаживания (или тормозище), неоправданный перерасход памяти.
Пару штук observable\observer ваше мобильное приложение выдержит. А вот с десяток, или, как в моём первом проекте с три десятка в одной view (vm), то уже начнутся заметные подтормаживания…
Могу писать о связке rx+xamarin.forms бесконечно долго :)) Но итог один — я крайне не доволен System.Reactive под мобильники.
Если нужна особая асинхронность, то лучше перейти на TPL или поюзать фитчи C#9.0. Меньшее количество задач в багтрекере вам обеспечено! :))
Да и вообще, System.Reactive уже пережил себя с приходом асинхронного программирования. Разве нет?
Разумеется, использование любого стороннего фреймворка добавляет накладных расходов — тут я спорить не буду. Поэтому и выбирается золотая середина между допустимыми «тормозами» и удобством программирования. В нашем случае Reactive UI нагрузил систему недостаточно, чтобы отказаться от его использования :)
Что-то наподобие интерфейса ICommand
и команд в WPF, только интеракции в нашем случае назначались на интерфейсные элементы не декларативно (как с командами в WPF), а программно, что показалось не очень удобным.
Было бы интересно узнать, а почему решили не использовать для подобных штук реактивные команды? ReactiveCommand<TInput, TOutput>
— это же реализация ICommand
на стероидах, с ThrownExceptions
, IsExecuting
, etc. Interactions же были задуманы, как один из способов реализации взаимодействий с модальными окнами, и на практике использовать эти штуки обычно доводится нечасто.
Перед решением не использовать реактивные команды мы не рассматривали этот вариант в принципе (из-за отсутствия опыта использования Reactive UI ранее он просто выпал из области рассмотрения).
Возможно, Ваш вариант с ReactiveCommand был бы более удачным решением (особенно, учитывая описанные недостатки интеракций). Я не имею абсолютно никаких нареканий к ICommand в WPF, и использовать то же самое в Xamarin лично для меня было бы более комфортно
Вообще с командами в ReactiveUI работать несколько более удобно, чем с объектами типа Interaction
. Привязывать команду модели представления к элементу интерфейса можно как в XAML-разметке — с помощью синтаксиса {Binding CommandName}
, — так и в коде на языках программирования C#, F#, или Visual Basic, с помощью extension-методов ReactiveUI, включая методы Bind
, BindCommand
, OneWayBind
, BindTo
. То есть можно делать так:
<Button x:Name="AwesomeButton"
Content="Hello, world!"
Command="{Binding AwesomeCommand}" />
Или так:
this.BindCommand(
ViewModel,
vm => vm.AwesomeCommand,
view => view.AwesomeButton);
Последний вариант хорош тем, что при переименовании свойства модели представления, к которой мы привязываем данные, мы узнаем о том, что что-то пошло не так, уже на этапе компиляции приложения. Причём для WPF, Windows Forms и Xamarin Forms это более актуально, чем для UWP или Avalonia, которые поддерживают compiled-биндинги. А на Xamarin.Android или Xamarin.iOS других вариантов в общем-то и нет. Дополнительно, можно подписываться на исключения, выброшенные экземплярами ReactiveCommand
, двумя способами — можно подписаться на исключения одной команды:
LoadUsers.ThrownExceptions.Subscribe(
exception => /* update property etc. */
);
Или на исключения всех команд и OAPH в приложении сразу:
RxApp.DefaultExceptionHandler = Observer.Create(
error => /* Handle errors. */
);
Такой подход, с одной стороны, позволяет сделать приложение более отказоустойчивым и научить его отправлять отчёты об ошибках куда-нибудь для дальнейшего анализа, а с другой — позволяет не писать try { } catch { }
блоки повсеместно в лямбдах, предлагая вместо этого написать реактивный пайплайн наподобие:
_errorMessage = Login // ReactiveCommand<TInput, TOutput>
.ThrownExceptions // Все исключения свалятся сюда.
.Select(exception => exception.Message)
.ToProperty(this, x => x.ErrorMessage);
Впрочем, впоследних версиях ReactiveUI должен быть доступен синтаксис BindInteraction
, позволяющий привязывать Interaction
к действиям более удобным образом:
// В файле *.xaml.cs:
this.BindInteraction(
ViewModel,
vm => vm.MyInteraction,
context => /* Обработчик взаимодействия. */);
Xamarin.Forms. Личный опыт использования