Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 1594 сообщений
Cообщения с меткой

команды - Самое интересное в блогах

Следующие 30  »
frenex

Заказ маек для команды по футболу

Суббота, 29 Августа 2015 г. 09:47 (ссылка)

Заказ маек для команды по футболу.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
suido

Мод для gta sa футболка футбольной команды

Среда, 26 Августа 2015 г. 19:26 (ссылка)

Мод для gta sa футболка футбольной команды.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
lenov_ru

Pixel Cup Soccer 16 v 1.0.1 (Full) » Клуб пользователей планшетов на ANDROID / Lenovo IdeaTab A2109 8GB / Samsung Galaxy Tab 2 7.0 / Asus Transformer TF700T / NVIDIA Tegra 3

Среда, 24 Августа 2016 г. 07:38 (ссылка)
lenov.ru/games/26148-pixel-...-full.html


Pixel Cup Soccer 16 - шикарный спортивный проект про футбол с пиксельной графикой в олдскульном стиле, что несказанно порадует всех ценителей \старины\. Разнообразные режимы, команды, турнир

Комментарии (0)КомментироватьВ цитатник или сообщество
rentsoft

Футболки команды houston rockets

Пятница, 22 Августа 2015 г. 00:11 (ссылка)

Футболки команды houston rockets.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
extea

Футболки с хоккеёной символикой команды металлург

Четверг, 21 Августа 2015 г. 01:14 (ссылка)

Футболки с хоккеёной символикой команды металлург.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
fabet

Футболки с логотипом команды по хоккею ертис картинки

Вторник, 19 Августа 2015 г. 03:18 (ссылка)

Футболки с логотипом команды по хоккею ертис картинки.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
trouvim

Купить футболку команды ливерпуль

Суббота, 15 Августа 2015 г. 15:14 (ссылка)

Купить футболку команды ливерпуль.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
presun

Футболки команды кубань

Суббота, 15 Августа 2015 г. 04:55 (ссылка)

Футболки команды кубань.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
voava

Футболки футбольной команды milan

Пятница, 14 Августа 2015 г. 23:38 (ссылка)

Футболки футбольной команды milan.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
formou

Отличаются ли цветом футболки капитанов футбольной команды

Пятница, 14 Августа 2015 г. 09:49 (ссылка)

Отличаются ли цветом футболки капитанов футбольной команды.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
lenov_ru

ZomboBus: Выживание v 1.5 » Клуб пользователей планшетов на ANDROID / Lenovo IdeaTab A2109 8GB / Samsung Galaxy Tab 2 7.0 / Asus Transformer TF700T / NVIDIA Tegra 3

Среда, 10 Августа 2016 г. 07:32 (ссылка)
lenov.ru/games/25984-zombob...-v-15.html


ZomboBus: Выживание - увлекательная стратегия в стиле \Tower Defense\ в которой геймеры примут участие в роли одного из членов экипажа боевого автобуса. Этот железный мутант на колёсах был р

Комментарии (0)КомментироватьВ цитатник или сообщество
starovar

Заказать футболку хоккейной команды салават юлаева с росписью играков

Суббота, 08 Августа 2015 г. 14:45 (ссылка)

Заказать футболку хоккейной команды салават юлаева с росписью играков.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
masterwen

Без заголовка

Среда, 03 Августа 2016 г. 21:26 (ссылка)
kinokonsta.ru/2015/3164-kil...?_utl_t=li


Киллджойс (2015) » Смотреть онлайн фильмы 2014 - 2016 , смотреть фильмы бесплатно в хорошем качестве

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
centde

Майка с названием команды lakers интернет магазин

Понедельник, 03 Августа 2015 г. 06:57 (ссылка)

Майка с названием команды lakers интернет магазин.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
hoabap

Футболка команды спартак

Пятница, 31 Июля 2015 г. 09:21 (ссылка)

Футболка команды спартак.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
prowdo

Футболки команды локомотив

Среда, 29 Июля 2015 г. 22:02 (ссылка)

Футболки команды локомотив.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
ivapet

Российская олимпийская сборная прибыла в Рио-де-Жанейро

Пятница, 29 Июля 2016 г. 10:39 (ссылка)
infopolk.ru/1/U/events/8142...9efd14bb02

Российская олимпийская сборная прибыла в Рио-де-Жанейро


В Рио-де-Жанейро приземлился самолёт с российскими спортсменами, которые в составе сборной примут участие в Олимпийских играх ...

Комментарии (0)КомментироватьВ цитатник или сообщество
wingrallu

Овечкин с футболкой команды

Четверг, 23 Июля 2015 г. 22:16 (ссылка)

Овечкин с футболкой команды.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
opetrov

На Украине новый государственный праздник – День вышивана Политикус InfoPolk.ru

Среда, 20 Июля 2016 г. 23:08 (ссылка)
infopolk.ru/1/U/events/8092...b63e01cc03

На Украине новый государственный праздник – День вышивана


О времена, о нравы. Каждая эпоха старается увековечить свои традиции, что отражается в отмечании тех или иных праздников и торжеств ...

Комментарии (0)КомментироватьВ цитатник или сообщество
ivapet

На Украине новый государственный праздник – День вышивана Политикус InfoPolk.ru

Среда, 20 Июля 2016 г. 21:57 (ссылка)
infopolk.ru/1/U/events/8092...9efd14bb02

На Украине новый государственный праздник – День вышивана



О времена, о нравы. Каждая эпоха старается увековечить свои традиции, что отражается в отмечании тех или иных праздников и торжеств ...
Комментарии (0)КомментироватьВ цитатник или сообщество
paibu

Майки водное поло команды

Воскресенье, 19 Июля 2015 г. 17:26 (ссылка)

Майки водное поло команды.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
lenov_ru

Bullet Party CS 2 : GO STRIKE v 1.1.1 » Клуб пользователей планшетов на ANDROID / Lenovo IdeaTab A2109 8GB / Samsung Galaxy Tab 2 7.0 / Asus Transformer TF700T / NVIDIA Tegra 3

Среда, 13 Июля 2016 г. 08:40 (ссылка)
lenov.ru/games/25667-bullet...v-111.html


Bullet Party CS 2 : GO STRIKE - продолжение популярного сетевого шутера от первого лица. Улучшенная графика, новые карты, ранги и звания, увеличенный арсенал оружия и многое другое ждёт гейм

Комментарии (0)КомментироватьВ цитатник или сообщество
Onem

«Миротворец» провоцирует агрессию

Вторник, 12 Июля 2016 г. 23:09 (ссылка)
infopolk.ru/1/U/events/8043...00fc74687c

«Миротворец» провоцирует агрессию


После прихода Порошенко и его команды к власти, были поэтапно закрыты все ресурсы, работающие на русском языке. ТВ, Интернет, радио – все, что выражало неправильную точку зрения ...

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Введение в ReactiveUI: изучаем команды

Понедельник, 11 Июля 2016 г. 14:13 (ссылка)

Часть 1: Введение в ReactiveUI: прокачиваем свойства во ViewModel

Часть 2: Введение в ReactiveUI: коллекции



Мы уже обсудили возможности ReactiveUI, связанные с работой со свойствами, выстраиванием зависимостей между ними, а также с работой с коллекциями. Это одни из основных примитивов, на базе которых строится разработка с применением ReactiveUI. Еще одним таким примитивом являются команды, которые мы и рассмотрим в этой части. Команды инкапсулируют действия, которые производятся в ответ на некоторое событие: обычно это запрос пользователя или какие-то отслеживаемые изменения. Мы узнаем, что можно сделать с помощью команд в ReactiveUI, обсудим особенности их работы и выясним, чем команды в ReactiveUI отличаются от команд, с которыми мы знакомы по WPF и его родственникам.

Но прежде чем перейти к командам, рассмотрим более широкие темы, касающиеся реактивного программирования в целом: связь между Task и IObservable, и что такое горячие и холодные последовательности.



Task vs. IObservable



Итак, проведем параллель между Task (+ async, await, вот это все) и IObservable. Нам это будет важно для понимания того, как работать с командами в ReactiveUI, но описываемый подход имеет более широкое применение и о нем не помешает знать. Итак: Task — это IObservable. Но они, безусловно, не эквивалентны: IObservable может решать гораздо больший круг задач.

Звучит как-то подозрительно, не правда ли? Давайте разбираться. Сразу посмотрим пример:

Task task = Task.Run(() =>
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Начинаем долгую задачу");
Thread.Sleep(1000);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Завершаем долгую задачу");
return "Результат долгой задачи";
});
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Делаем что-то до начала ожидания результата задачи");
string result = task.Result;
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Полученный результат: " + result);


Мы создали задачу, она выполнится асинхронно и не помешает нам делать что-то еще сразу после ее запуска, не дожидаясь завершения. Результат предсказуем:

18:19:47 Делаем что-то до начала ожидания результата задачи

18:19:47 Начинаем долгую задачу

18:19:48 Завершаем долгую задачу

18:19:48 Полученный результат: Результат долгой задачи



Первые 2 строки выведутся сразу и могут иметь разный порядок, как повезет.

А теперь перепишем на IObservable:

IObservable task = Observable.Start(() =>
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Начинаем долгую задачу");
Thread.Sleep(1000);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Завершаем долгую задачу");
return "Результат долгой задачи";
});
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Делаем что-то до начала ожидания результата задачи");
string result = task.Wait(); // блокирующее ожидание завершения и возврат результата
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Полученный результат: " + result);


Разница в двух строках: IObservable вместо Task, Observable.Start() вместо Task.Run() и task.Wait() вместо task.Result. Результат работы же точно такой же.



Посмотрим еще один известный прием с запуском действия после завершения задачи:

//Task
task.ContinueWith(t => Console.WriteLine(DateTime.Now.ToLongTimeString() + " Полученный результат: " + t.Result));
//IObservable
task.Subscribe(t => Console.WriteLine(DateTime.Now.ToLongTimeString() + " Полученный результат: " + t));


Разницы, опять же, практически нет.



Получается, Task можно представить через IObservable, который выдаст один элемент и сигнал завершения. Большой философской и архитектурной разницы между такими подходами нет, и можно пользоваться любым. Даже async/await доступен в обоих случаях: если мы в асинхронном методе должны получить результат из IObservable, можно не делать блокирующее ожидание через метод Wait(), как в примере, а использовать await. Более того, эти два подхода можно совмещать, трансформировать одно представление в другое и пользоваться плюсами обоих.



Горячие и холодные последовательности



Обсудим еще один вопрос, касающийся работы с наблюдаемыми последовательностями (observable). Они могут быть двух типов: холодные (cold) и горячие (hot). Холодные последовательности пассивны и начинают генерировать уведомления по запросу, в момент подписки на них. Горячие же последовательности активны и не зависят от того, подписан ли на них кто-то: уведомления все равно генерируются, просто иногда они уходят в пустоту.

Тики таймера, события движения мыши, приходящие по сети запросы — это горячие последовательности. Подписавшись на них в некоторый момент, мы начнем получать актуальные уведомления. Подпишутся 10 наблюдателей — уведомления будут доставляться каждому. Вот пример с таймером:





Холодная же последовательность — это, например, запрос в базу данных или чтение файла построчно. Запрос или чтение запускается при подписке, и с каждой новой полученной строкой вызывается OnNext(). Когда строки закончатся, вызовется OnComplete(). При повторной подписке все повторяется снова: новый запрос в БД или открытие файла, возврат всех полученных результатов, сигнал завершения:








Классические команды...



Теперь перейдем к нашей сегодняшней теме — к командам. Команды, как я уже упомянул, инкапсулируют действия, совершаемые в ответ на некоторые события. Таким событием может быть нажатие пользователем кнопки «Сохранить»; тогда инкапсулируемым действием станет операция сохранения чего-то. Но команда может быть исполнена не только в ответ на явное действие пользователя или связанные с ним косвенные события. Сигнал от таймера, срабатывающего раз в 5 минут независимо от пользователя, тоже может инициировать ту же самую команду «Сохранить». И хотя обычно команды используются именно для действий, которые так или иначе совершает пользователь, не стоит пренебрегать их использованием и в других случаях.

Также команды позволяют выяснить, доступно ли в данный момент выполнение. Например, мы хотим, чтобы сохранение было доступно не всегда, а только когда заполнены все обязательные поля формы, и от доступности команды зависело бы, активна ли кнопка в интерфейсе.

Посмотрим, что представляет собой интерейс команды ICommand:

public interface ICommand
{
event EventHandler CanExecuteChanged;
bool CanExecute(object parameter);
void Execute(object parameter);
}


Execute, очевидно, выполняет команду. Ему можно передать параметр, но этой возможностью не стоит пользоваться, если необходимое значение можно получить внутри самой команды (например, взять из ViewModel). Дальше мы поймем, почему так. Но, конечно, есть и ситуации, когда передача параметра — самый приемлемый вариант.

CanExecute проверяет, доступно ли выполнение команды в данный момент. У него тоже есть параметр, и тут все то же самое, что и с Execute. Важно то, что CanExecute с неким значением параметра разрешает или запрещает выполнение команды только с таким же значением параметра, для других значений результат может отличаться. Стоит также помнить, что Execute перед выполнением действий не проверяет CanExecute на возможность выполнения, это задача вызывающего кода.

Событие CanExecuteChanged возникает, когда статус возможности выполнения меняется и стоит перепроверить CanExecute. Например, когда все поля в форме были заполнены и стало возможным сохранение, нужно инициировать включение кнопки в интерфейсе. Кнопка с привязанной командой узнает об этом именно так.



… и что с ними не так



Первая проблема — это то, что событие CanExecuteChanged не говорит о том, для какого значения параметра статус возможности выполнения изменился. Это та самая причина, по которой использования параметров при вызове Execute/CanExecute стоит избегать: интерфейс ICommand в отношении параметров не особо согласован. С реактивными же командами, как мы увидим, этот подход вообще не ужился.



Вторая проблема — Execute() возвращает управление только после завершения выполнения команды. Когда команда выполняется долго — пользователь расстраивается, потому что он сталкивается с зависшим интерфейсом.

Кому понравится такое?
В программе есть кнопка запуска команды, вывод лога и прогресс-бар, который в нормальной ситуации должен постоянно двигаться. Команда при запуске пишет в лог текущее время, полторы секунды что-то делает (например, загружает данные) и пишет время завершения.



Прогресс-бар останавливается, лог обновляется только по завершении команды, интерфейс зависает. Нехорошо получилось…



Как спасти ситуацию? Конечно, можно реализовать команду так, чтобы она только инициировала выполнение нужных действий в другом потоке и возвращала управление. Но тогда возникает другая проблема: пользователь может нажать на кнопку еще раз и запустить команду снова, еще до завершения предыдущей. Усложним реализацию: сделаем так, чтобы CanExecute возвращал false, пока задача выполняется. Интерфейс не зависнет, команда не запустится параллельно несколько раз, мы добились своего. Но все это нужно делать своими руками. А в ReactiveUI команды уже умеют все это и многое другое.






Реактивные команды



Познакомимся с ReactiveCommand. Не перепутайте: есть еще non-generic реализация с таким же именем: ReactiveCommand (она находится в пространстве имен ReactiveUI.Legacy, и, очевидно, является устаревшей). Этот generic параметр обозначает не тип парамера, а тип результата, но мы вернемся к этому позже.



Сразу попробуем создать и запустить команду, опустив для начала все, что связано с CanExecute. Заметьте, что обычно мы вообще не создаем команды напрямую через оператор new, а пользуемся статическим классом ReactiveCommand, предоставляющим нужные методы.

var command = ReactiveCommand.Create();
command.Subscribe(_ =>
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Начинаем долгую задачу");
Thread.Sleep(1000);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Завершаем долгую задачу");
});
command.Execute(null);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " После запуска команды");
Console.ReadLine();


Метод ReactiveCommand.Create() создает синхронные задачи, они имеют тип ReactiveCommand. Execute() возвращает управление только после завершения работы:

19:01:07 Начинаем долгую задачу

19:01:08 Завершаем долгую задачу

19:01:08 После запуска команды



Позже мы рассмотрим способы создания асинхронных команд, а пока взглянем на контроль возможности выполнения команды.



Возможность выполнения команды



Обсудим CanExecute и связанные с ним особенности. Кроме того, что мы уже видели (метод CanExecute и событие CanExecuteChanged), ReactiveCommand предоставляет последовательности IsExecuting и CanExecuteObservable:

var command = ReactiveCommand.Create();
command.Subscribe(_ => Console.WriteLine("Выполняется команда"));

command.CanExecuteChanged += (o, a) => Console.WriteLine("CanExecuteChanged event: now CanExecute() == {0}", command.CanExecute(null));
command.IsExecuting.Subscribe(isExecuting => Console.WriteLine("IsExecuting: {0}", isExecuting));
command.CanExecuteObservable.Subscribe(canExecute => Console.WriteLine("CanExecuteObservable: {0}", canExecute));

Console.WriteLine("Подписались на все, запускаем команду...");
command.Execute(null);
Console.WriteLine("После запуска команды");


IsExecuting: False

CanExecuteObservable: False

CanExecuteObservable: True

CanExecuteChanged event: now CanExecute() == True

Подписались на все, запускаем команду…

IsExecuting: True

CanExecuteChanged event: now CanExecute() == False

CanExecuteObservable: False

Выполняется команда

IsExecuting: False

CanExecuteChanged event: now CanExecute() == True

CanExecuteObservable: True

После запуска команды



На то, что происходит сразу после подписки и до запуска команды, можно особенно не обращать внимание: это инициализация. Фактически нам сразу при подписке возвращают текущее состояние (получается холодный первый элемент и горячие последующие). Причем CanExecuteObservable изначально установлен в false. Похоже, что при подписке сначала нам дают это значение, а потом команда определяет, что мы не предоставлили механизм определения доступности, и делает команду доступной по-умолчанию.

Судя по выводу программы, команда уже бывает недоступна во время ее выполнения. Это особенно актуально для асинхронных команд: так они не будут запущены параллельно несколько раз. Таким образом, CanExecute, CanExecuteObservable и событие CanExecuteChanged зависят не только от того, что мы предоставим для расчета, но и от того, выполняется ли сейчас команда. IsExecuting же предоставляет именно информацию о том, выполняется ли команда в данный момент, и это можно использовать, например, для показа какого-то индикатора работы.



Давайте теперь предоставим команде информацию о том, когда она может выполняться. Для этого у каждого метода создания команд в классе ReactiveCommand есть перегрузки, принимающие IObservable canExecute. Команда подпишется на эту последовательность и при получении изменений будет актуализировать свою информацию о доступности выполнения. Смотрим:

var subject = new Subject();
var command = ReactiveCommand.Create(subject);

command.CanExecuteChanged += (o, a) => Console.WriteLine("CanExecuteChanged event: now CanExecute() == {0}", command.CanExecute(null));
command.CanExecuteObservable.Subscribe(canExecute => Console.WriteLine("CanExecuteObservable: {0}", canExecute));

Console.WriteLine("Делаем выполнение доступным");
subject.OnNext(true);
Console.WriteLine("Делаем выполнение недоступным");
subject.OnNext(false);
Console.WriteLine("Еще раз делаем выполнение недоступным");
subject.OnNext(false);


Subject здесь — это observable, который мы контролируем своими руками, выдавая через него нужные значения команде. Как минимум это очень удобно при тестировании. Мы подписываемся на все, делаем выполнение доступным, а потом два раза недоступным. Какой результат мы получим?

CanExecuteObservable: False

Делаем выполнение доступным

CanExecuteChanged event: now CanExecute() == True

CanExecuteObservable: True

Делаем выполнение недоступным

CanExecuteChanged event: now CanExecute() == False

CanExecuteObservable: False

Еще раз делаем выполнение недоступным



Вроде все ожидаемо. Изначально выполнение недоступно. Потом команда начинает реагировать на изменения, которые мы делаем. Здесь стоит только отметить, что когда мы несколько раз подряд посылаем одно и то же состояние доступности, команда игнорирует повторы. Заметим также, что CanExecuteObservable — это просто последовательность значений типа bool, и здесь возникает несовместимость с тем, что у метода CanExecute есть параметр. В ReactiveCommand он просто игнорируется.



Способы вызвать команду



Мы уже видели вызов команды методом Execute(). Посмотрим на другие способы:



IObservable ExecuteAsync(object parameter)

Тут кроется одна особенность: выполнение команды не начнется, пока на результат ExecuteAsync() не будет совершена подписка. Воспользуемся им:

command.ExecuteAsync().Subscribe();


Однако синхронная команда от этого не становится асинхронной. Конечно, ExecuteAsync() вернет управление сразу, но выполнение еще не стартовало! А Subscribe(), который его стартует, вернет управление только после завершения команды. Фактически сейчас мы написали эквивалент Execute(). Впрочем, это закономерно, ведь ExecuteAsync() возвращает холодную последовательность и подписка на нее инициирует выполнение нашей долгой задачи. А выполняется она в текущем потоке. Хотя это можно исправить, явно указав, где выполнять подписку:

command.ExecuteAsync().SubscribeOn(TaskPoolScheduler.Default).Subscribe();


Теперь планировщик TPL отвечает за выполнение подписки. Соответственно, подписка будет выполнена в чем-то вроде Task.Run(), и все заработает как надо. Но заниматься таким в реальности не стоит, и этот пример лишь показывает одну из возможностей. Всяких же планировщиков много, и однажды мы коснемся и этой темы.



Task ExecuteAsyncTask(object parameter)

В отличие от ExecuteAsync(), этот метод сразу запускает команду. Пробуем:

command.ExecuteAsyncTask();


Нам вернули Task<>, но счастья в жизни все нет. ExecuteAsyncTask() тоже возвращает управление только после завершения работы команды, и дает нам уже завершенную задачу. Какая-то подстава.



InvokeCommand()

Этот способ позволяет удобно настроить вызов команды при появлении сигнала в последовательности (например, изменение свойства). Примерно так:

this.WhenAnyValue(x => x.FullName).Where(x => !string.IsNullOrEmpty(x)).InvokeCommand(this.Search); // указываем конкретный экземпляр команды
this.WhenAnyValue(x => x.FullName).Where(x => !string.IsNullOrEmpty(x)).InvokeCommand(this, x => x.Search); // указываем, где каждый раз брать экземпляр команды


Пока мы так и не нашли способ выполнить команду асинхронно. Конечно, можно пользоваться методом ExecuteAsync() и назначать планировщик для выполнения подписки, но это костыль. Тем более WPF про этот метод не знает и будет по-прежнему вызывать Execute() и вешаться.



Асинхронные реактивные команды



Синхронные команды имеют смысл, когда действия выполняются быстро и нет смысла усложнять. А для долгих задач нужны асинхронные команды. Здесь нам в помощь два метода: ReactiveCommand.CreateAsyncObservable() и ReactiveCommand.CreateAsyncTask(). Разница между ними только в том, через что выражается выполняемое действие. Возвращаемся к первому разделу статьи и тому, как можно представить асинхронные задачи.



Посмотрим CreateAsyncObservable:

var action = new Action(() =>
{
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Начинаем долгую задачу");
Thread.Sleep(1000);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " Завершаем долгую задачу");
});
var command = ReactiveCommand.CreateAsyncObservable(_ => Observable.Start(action));

Console.WriteLine(DateTime.Now.ToLongTimeString() + " Запускаем команду...");
command.Execute(42);
Console.WriteLine(DateTime.Now.ToLongTimeString() + " После запуска команды");
Console.ReadLine();


2:33:50 Запускаем команду…

2:33:50 После запуска команды

2:33:50 Начинаем долгую задачу

2:33:51 Завершаем долгую задачу



Ура! Execute уже не блокируется до завершения выполнения команды, и интерфейс не будет зависать. С ExecuteAsync и ExecuteAsyncTask все аналогично: блокировок нет.



Теперь СreateAsyncTask:

var command = ReactiveCommand.CreateAsyncTask(_ => Task.Run(action));
var command = ReactiveCommand.CreateAsyncTask(_ => doSomethingAsync()); // метод возвращает Task
var command = ReactiveCommand.CreateAsyncTask(async _ => await doSomethingAsync());


У обоих описанных методов много перегрузок, поддерживающих, например, передачу CanExecuteObservable или возможность отмены.

Кроме того, из асинхронной команды можно возвращать результат. Generic-параметр T из ReactiveCommand — это как раз тип результата работы команды:

ReactiveCommand command = ReactiveCommand.CreateAsyncTask(_ => Task.Run(() => 42));
var result = await command.ExecuteAsync(); // result == 42


И можно сразу направить его куда-нибудь:

var command = ReactiveCommand.CreateAsyncTask(_ => Task.Run(() => 42));
command.Subscribe(result => _logger.Log(result));
_answer = command.ToProperty(this, this.Answer); // Меняет значение свойства на результат выполнения команды (ObservableToPropertyHelper)


Гарантируется, что результат возвращается в потоке UI. Поэтому, кстати, выполнять в Subscribe какие-то долгие действия как реакцию на выполнение команды противопоказано. В случае синхронных команд собственный результат вернуть нельзя, команда имеет тип ReactiveCommand и возвращаться будут значения, с которыми была запущена команда.



Ловим исключения, возникающие при работе команд



Исключения при работе команд могут возникать постоянно, особенно если речь идет о какой-нибудь загрузке данных. Соответственно, надо научиться их ловить и обрабатывать. Где и как это делать?



Синхронные команды

var command = ReactiveCommand.Create();
command.Subscribe(_ => { throw new InvalidOperationException(); });
command.ThrownExceptions.Subscribe(e => Console.WriteLine(e.Message));
command.Execute(null); //не бросает исключение
command.ExecuteAsync().Subscribe(); //сразу бросит InvalidOperationException
await command.ExecuteAsyncTask(); //сразу бросит InvalidOperationException


Так как вызовы всех методов синхронные, стоило бы ожидать, что они и бросят исключения. Но все не так просто. Execute() на самом деле не бросает исключения. Он реализован так, что все исключения просто глотаются. Другие два метода бросают исключения сразу, как и ожидалось.



С асинхронными командами все гораздо интереснее

ReactiveCommand предоставляет последовательность ThrownExceptions, через которую приходят возникшие при исполнении асинхронных команд исключения. Разницы между командами на базе Observable и Task здесь нет. Создадим команды для нашего эксперимента:

var command = ReactiveCommand.CreateAsyncTask(_ => Task.Run(() => { throw new InvalidOperationException(); })); /* 1 вариант */ 
var command = ReactiveCommand.CreateAsyncObservable(_ => Observable.Start(() => { throw new InvalidOperationException(); })); /* 2 вариант */
command.ThrownExceptions.Subscribe(e => Console.WriteLine(e.Message));


И попробуем разные способы вызвать команду:

command.Execute(null); //исключение придет через ThrownExceptions

command.ExecuteAsyncTask(); //исключение InvalidOperationException бросится когда-то в будущем (Task с необработанным исключением)
command.ExecuteAsync().Subscribe(); //исключение InvalidOperationException бросится когда-то в будущем, аналогично Task с необработанным исключением

await command.ExecuteAsync(); //сразу бросит InvalidOperationException И исключение придет через ThrownExceptions
await command.ExecuteAsyncTask(); //сразу бросит InvalidOperationException И исключение придет через ThrownExceptions

var subj = new Subject();
subj.InvokeCommand(command);
subj.OnNext(Unit.Default); //исключение придет через ThrownExceptions


Если же мы так или иначе подпишемся на саму команду (например, command.ToProperty(...)), то при возникновении исключения в команде OnError() не отсылается.



В приведенном примере странными кажутся примеры, в которых исключения возникнут «когда-то». В TPL это нужно было, чтобы неперехваченные исключения не исчезали без следа. Тут же можно было передать их через ThrownExceptions и не бросать «в будущем». Но такова реализация, и в следующей версии ReactiveUI вроде как что-то в этом отношении поменяется.



Отмена асинхронных команд



Команды, которые могут долго выполняться, хорошо бы уметь отменять. Для этого есть много способов. Создадим асинхронную команду, которая в цикле будет выводить сообщение, пока ее не отменят:

var command = ReactiveCommand.CreateAsyncTask(async (a, t) =>
{
while (!t.IsCancellationRequested)
{
Console.WriteLine("работаем");
await Task.Delay(300);
}
Console.WriteLine("отмена");
});


Первый способ отмены — отмена подписки, созданной на основе ExecuteAsync():

var disposable = command.ExecuteAsync().Subscribe();
Thread.Sleep(1000);
disposable.Dispose();


Второй способ — передача токена через ExecuteAsyncTask():

var source = new CancellationTokenSource();
command.ExecuteAsyncTask(ct: source.Token);
Thread.Sleep(1000);
source.Cancel();


Но что делать, если мы хотим отменять команду, которая запускается методом Execute(), то есть при вызове, например, самим WPF? Это тоже несложно сделать, для этого нам понадобится обернуть Task в IObservable и использовать метод TakeUntil(). Приведу пример с вызовом другой команды для отмены:

Func action = async (ct) =>
{
while (!ct.IsCancellationRequested)
{
Console.WriteLine("работаем");
await Task.Delay(300);
}
Console.WriteLine("отмена");
};

IReactiveCommand cancelCommand = null;
var runCommand = ReactiveCommand.CreateAsyncObservable(_ => Observable.StartAsync(action).TakeUntil(cancelCommand));
cancelCommand = ReactiveCommand.Create(runCommand.IsExecuting);

runCommand.Execute(null);

Thread.Sleep(1000);
cancelCommand.Execute(null);


Команда выполняется до появления в последовательности cancelCommand очередного уведомления. По сути на месте cancelCommand может быть даже не команда, а любая наблюдаемая последовательность.



Во всех этих способах есть одна тонкость: когда мы инициировали отмену, команда сразу считается завершенной и доступной для повторного выполнения, но если токен отмены игнорируется задачей, то внутри еще могут продолжаться какие-то действия. Это тоже стоит учитывать, если команда становится отменяемой. Особенно это касается случаев, когда мы отменяем команду, в которой вообще нет Task:

Action action = () => { ... };
var runCommand = ReactiveCommand.CreateAsyncObservable(_ => Observable.Start(action).TakeUntil(cancelCommand));


Здесь action будет выполняться и после того, как мы отменим выполнение и команда снова станет доступной для вызова. Только происходить это будет за занавесом, и может приводить к весьма неожиданным результатам.



Объединение команд



Можно легко создавать команду, вызывающую другие команды:

RefreshAll = ReactiveCommand.CreateCombined(RefreshNotifications, RefreshMessages);


В этом случае команда выполнима, когда выполнимы все команды из переданного набора. Также есть перегрузка, в которую можно передать отдельный canExecute для указания, когда команда может выполняться. В таком случае учитывается и возможность выполнения каждой команды, и переданный параметр.






Пример работы с командами



Давайте напишем небольшой пример, показывающий использование команд.

Мы сделаем поиск. Ну, условный поиск. На самом деле мы будем полторы секунды имитировать деятельность и возвращать в качестве результата коллекцию из нескольких модификаций запроса. Также мы поддержим отмену поиска, очистку старого результата при начале нового поиска и возможность выполнять поиск автоматически при изменении входных данных.

Смотрим вьюмодель:

public class SearchViewModel : ReactiveObject
{
[Reactive] public string SearchQuery { get; set; }

[Reactive] public bool AutoSearch { get; set; }

private readonly ObservableAsPropertyHelper> _searchResult;
public ICollection SearchResult => _searchResult.Value;

public IReactiveCommand> Search { get; }

public IReactiveCommand CancelSearch { get; }

public SearchViewModel()
{
Search = ReactiveCommand.CreateAsyncObservable(
this.WhenAnyValue(vm => vm.SearchQuery).Select(q => !string.IsNullOrEmpty(q)),
_ => Observable.StartAsync(ct => SearchAsync(SearchQuery, ct)).TakeUntil(CancelSearch)
);

CancelSearch = ReactiveCommand.Create(Search.IsExecuting);

Observable.Merge(
Search,
Search.IsExecuting.Where(e => e).Select(_ => new List()))
.ToProperty(this, vm => vm.SearchResult, out _searchResult);

this.WhenAnyValue(vm => vm.SearchQuery)
.Where(x => AutoSearch)
.Throttle(TimeSpan.FromSeconds(0.3), RxApp.MainThreadScheduler)
.InvokeCommand(Search);
}

private async Task> SearchAsync(string query, CancellationToken token)
{
await Task.Delay(1500, token);
return new List() { query, query.ToUpper(), new string(query.Reverse().ToArray()) };
}
}


Конечно, здесь есть недочеты. Один из них в автопоиске. Если во время выполнения поиска пользователь изменит запрос, текущий поиск не будет остановлен и сначала завершится он, а потом уже выполнится поиск по новому запросу. Впрочем, исправить это — дело пары строк. Или, скажем, странно не очищать результаты поиска в случае, когда пользователь стер весь запрос. Но такие комплексные примеры оставим на следующие части, а пока ограничимся существующей логикой. Еще раз обращу внимание на то, что в общем-то не самое примитивное поведение нашего поисковика сосредоточено в одном месте и описывается достаточно кратко и понятно.



Посмотрим на XAML:























Auto search







Вопрос здесь может вызвать ProgressBar. Я хотел, чтобы он включался в процессе поиска. Но в команде Search свойство IsExecuting — не bool, а последовательность, и сделать к ней привязку в XAML не выйдет. Поэтому привязку выполним в конструкторе нашей вьюхи:

public partial class MainWindow : Window
{
public SearchViewModel ViewModel { get; }

public MainWindow()
{
ViewModel = new SearchViewModel();
InitializeComponent();

this.WhenAnyObservable(w => w.ViewModel.Search.IsExecuting).BindTo(SearchExecutingProgressBar, pb => pb.IsIndeterminate);
}
}


Да, в ReactiveUI есть поддержка таких вот биндингов, и по идее я мог сделать их все таким образом. Но о биндингах мы поговорим в другой раз, а пока я ограничился только тем, без чего не обойтись.



Посмотрим на результат






Ура! Работает как надо, интерфейс не виснет во время поиска, отмена работает, автопоиск работает, заказчик в экстазе и дает тройную премию.






In the next episode



Итак, подведем небольшой итог. В этой части мы выяснили, какая связь есть между Task и IObservable. Сравнили горячие и холодные последовательности. Но нашей основной темой были команды. Мы научились создавать синхронные и асинхронные команды и вызывать их разными способами. Выяснили, как включать и выключать возможность их выполнения, а также как перехватывать ошибки в асинхронных командах. Кроме того, мы разобрались, как отменять асинхронные команды.

Я хотел в этой части затронуть тестирование вьюмодели, но как-то не рассчитал, что команды растянутся в такую простыню. Поэтому в этот раз его не будет. В следующей же части мы рассмотрим либо привязки, либо тестирование и планировщики.

Не переключайтесь!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/305350/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
depba

Футболки с логотипом команды санкт петербург

Среда, 09 Июля 2015 г. 02:21 (ссылка)

Футболки с логотипом команды санкт петербург.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
formou

Клубные майки хоккейной команды бостон

Вторник, 08 Июля 2015 г. 01:58 (ссылка)

Клубные майки хоккейной команды бостон.


Читать далее
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
borodas93

Без заголовка

Четверг, 07 Июля 2016 г. 11:32 (ссылка)

Это цитата сообщения Joker-6 Оригинальное сообщение

Коды и команды операторов




Полезно для всех!

5CzLrkbN944 (640x480, 290Kb)



Читать далее...
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
ovdadub

Выкрутасы - сбор команды

Воскресенье, 03 Июля 2016 г. 16:47 (ссылка)




.

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<команды - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda