Nano Hash - криптовалюты, майнинг, программирование

ReactiveUI — использование планировщика в обработчике взаимодействия

Я хочу отображать диалоговое окно предупреждения с двумя кнопками при возникновении ошибки. Насколько мне известно, вот как это сделать, используя свойство Interaction:

this.ViewModel.ConnectionError.RegisterHandler(interaction =>
{
    var retry = await this.DisplayAlert("Connection failed", "Do you want to retry?", "RETRY", "ABORT");
    if (retry)
        interaction.SetOutput(DevicesViewModel.ErrorRecoveryOption.Retry);
    else
        interaction.SetOutput(DevicesViewModel.ErrorRecoveryOption.Abort);
});

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

this.ViewModel.ConnectionError.RegisterHandler(interaction =>
{
    RxApp.MainThreadScheduler.ScheduleAsync(interaction, async (scheduler, i, cancelationToken) =>
    {
        this.Log().Debug("ScheduleAsync");
        var retry = await this.DisplayAlert("Connection failed", "Do you want to retry?", "RETRY", "ABORT");
        if (retry)
            i.SetOutput(DevicesViewModel.ErrorRecoveryOption.Retry);
        else
            i.SetOutput(DevicesViewModel.ErrorRecoveryOption.Abort);

        return Disposable.Empty;
    });
});

Я вижу сообщение журнала в консоли, но диалоговое окно не отображается, и приложение аварийно завершает работу внутри ReactiveUI.dll. Что я делаю неправильно?


Ответы:


1

Если вы изучите детали краха, я подозреваю, что вы обнаружите, что он жалуется на то, что ничто не обработало взаимодействие. Причина этого в том, что ваш зарегистрированный обработчик является синхронным. Конечно, он запускает асинхронную работу, но ReactiveUI не дает возможности дождаться завершения этой работы.

Вы можете убедиться в этом, взглянув на перегрузку RegisterHandler, разрешенную вашим вызовом. Вы обнаружите, что это RegisterHandler(Action<InteractionContext<TInput, TOutput>>). Другими словами, «зарегистрируйте обработчик, который принимает контекст и синхронно обрабатывает взаимодействие.

Что вы хотите сделать, так это вызвать один из асинхронных методов RegisterHandler:

  • RegisterHandler(Func<InteractionContext<TInput, TOutput>, Task>)
  • RegisterHandler(Func<InteractionContext<TInput, TOutput>, IObservable<Unit>>)

Есть разные способы написать логику для этого. Я склонен предпочитать Rx как средство выражения асинхронности, поэтому я бы написал это так:

this
    .ViewModel
    .ConnectionError
    .RegisterHandler(
        context =>
            Observable
                .Start(
                    () => Unit.Default,
                    RxApp.MainThreadScheduler)
                .SelectMany(_ => this.DisplayAlert("Connection failed", "Do you want to retry?", "RETRY", "ABORT"))
                .Do(result => context.SetOutput(result ? ErrorRecoveryOption.Retry : ErrorRecoveryOption.Abort)));

Вызов Observable.Start — это своего рода хак, чтобы направить нас в нужную ветку, и я бы на вашем месте рассмотрел способы очистки этого. В частности, я бы посмотрел на инициирование взаимодействия в правильном потоке. То есть все, что вызывает Handle (вероятно, ваша виртуальная машина), должно делать это в потоке пользовательского интерфейса. Несмотря на то, что вы несете ответственность за выполнение команд в правильном потоке, Handle то же самое.

13.12.2016
  • Как и вы, я также предпочитаю синтаксис Rx для выражения асинхронности, но мне не хватало наблюдаемого трюка Unit. Никогда, хотя об этом. Вам нужно добавить .Select(_ =› Unit.Default) сразу после оператора Do, иначе будет использоваться перегрузка Action. Он все еще падает, но теперь я вижу исключение: неверный дескриптор окна. Этот API должен вызываться из потока с CoreWindow или окно должно быть задано явно. в 14.12.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..