OnPropertyChanged работает неправильно в Blazor (MAUI Hybrid)

Я зарегистрировал службу в MauiProgram.cs:

builder.Services.AddSingleton<NetworkStatusService>();

класс обслуживания:

public class NetworkStatusService : INotifyPropertyChanged
{
    private NetwStatus _netwStat;
    public NetwStatus NetwStat
    {
        get => _netwStat;
        set
        {
            if (_netwStat != value)
            {
                _netwStat = value;
                OnPropertyChanged(nameof(NetwStat));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public async Task CheckNetw()
    {
        NetwStat = NetwStatus.Loading;

        await Task.Delay(1000);

        if (await SomeClass.CheckDBConnection())
            NetwStat = NetwStatus.Success;
        else
            NetwStat = NetwStatus.Fail;
    }
}

моя упрощенная страница Blazor будет выглядеть следующим образом:

@page "/LoginComponent"
<div class = "Grid">
    @switch (NetworkStatusService.NetwStat)
    {
        case NetwStatus.Loading:
            <h6 style = "font-size:0.8rem; margin-bottom:-12px; color:coral">Trying to connect...</h6>
            break;
        case NetwStatus.Success:
            <h6 style = "font-size:0.8rem; margin-bottom:-12px; color:green">Connected uccessfully.</h6>
            break;
        case NetwStatus.Fail:
            <h6 style = "font-size:0.8rem; margin-bottom:-12px; color:red">Connection failed.</h6>
            break;
        default:
            break;
    }    ‌ ‌
    <i @onclick = "ViewModel.btnNetwOkCommand.ExecuteAsync">refresh</i>
</div>

команда, очевидно, запустит NetworkStatusService.CheckNetw()

но он НИКОГДА не переходит в режим «Пытаюсь подключиться...». он просто ждет и меняется либо на успех, либо на неудачу. Это очень расстраивает, я начинаю ненавидеть свою карьеру.

...использовали ли вы пошаговый отладчик для исследования проблемы? Если да, то расскажите, пожалуйста, что именно произошло внутри OnPropertyChanged? Если нет, то почему?

Dai 11.08.2024 19:05

@Дай, это очень расстраивает, оно полностью работало как локальное свойство в моей ViewModel, но перестало работать после того, как я переместил его в сервис... заставляет меня ненавидеть .net, они по какой-то причине превращают каждую простую задачу в головную боль

ParSa 11.08.2024 19:46

Я понимаю, что это расстраивает, но вы не ответили на мои вопросы...

Dai 11.08.2024 19:47

@Dai Я попробую отладить это завтра на работе и сообщу вам как можно скорее, спасибо, что заметили это

ParSa 11.08.2024 19:47

@Dai хаха ты ответил мне так быстро, что я едва успел напечатать второй комментарий

ParSa 11.08.2024 19:48
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
50
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Именно поэтому я считаю, что INotifyPropertyChanged не так хорошо работает с Blazor. Эта строка эквивалентна async void:

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

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

В OnPropertyChanged() вам придется вызвать StateHasChanged(), но это защищенный метод страницы. Это означает, что вам понадобится какая-то уродливая связь IView для передачи ViewModel. И сантехника для этого.

ох чувак, ты сказал мое сердце, разве они не должны это просто исправить? так много ненужных сложностей в Блазоре/Мауи. изменил свой код тысячей способов и остался на работе еще на 4 часа сегодня только для того, чтобы завтра услышать «ты отстаешь». Вероятно, мне следует начать переходить на что-то другое, кроме .net.

ParSa 11.08.2024 23:52

Что ж, сначала рассмотрите возможность использования Blazor без MVVM или, по крайней мере, без INotifyPropertyChanged. Обратите внимание: я никогда не использовал Blazor/MAUI, но знаю WPF и XAML. Blazor — это другая платформа с более простой привязкой к данным и событиям. Меньше абстракций, но очень полезно. Плывите по течению.

Henk Holterman 12.08.2024 00:13

Ну, не идеально, но я добавил это на свою страницу OnInitializeAsync:

NetworkStatusService.PropertyChanged += (sender, args) => InvokeAsync(StateHasChanged);

и это работает.

Это относительно простой обходной путь, я предполагал нечто гораздо большее.

Henk Holterman 12.08.2024 08:52

Я отвечал на этот вопрос, пока вы опубликовали этот ответ. Смотрите мой ответ, как правильно реализовать это с помощью IDisposable, чтобы удалить обработчик при уничтожении компонента.

MrC aka Shaun Curtis 12.08.2024 10:13

@MrCakaShaunCurtis, спасибо! именно так и надо делать.

ParSa 12.08.2024 12:08
Ответ принят как подходящий

Вам нужно подключить компонент к событию NetworkStatusService следующим образом:

@page "/"
@using System.ComponentModel
@inject NetworkStatusService NetworkStatusService
@implements IDisposable

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<div class = "m-2">
    @switch (NetworkStatusService.NetwStat)
    {
        case NetwStatus.Loading:
            <h6 class = "alert alert-warning" >Trying to connect...</h6>
            break;
        case NetwStatus.Success:
            <h6 class = "alert alert-success">Connected uccessfully.</h6>
            break;
        case NetwStatus.Fail:
            <h6 class = "alert alert-danger">Connection failed.</h6>
            break;
        default:
            break;
    }    ‌ ‌
    <button class = "btn btn-primary" @onclick = "ExecuteAsync">refresh</button>
</div>

@code {
    protected override void OnInitialized()
    {
        this.NetworkStatusService.PropertyChanged += OnPropertyChanged;
    }

    private void OnPropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        this.InvokeAsync(this.StateHasChanged);
    }

    private async Task ExecuteAsync()
    {
        await NetworkStatusService.CheckNetw();
    }

    public void Dispose()
    {
        this.NetworkStatusService.PropertyChanged -= OnPropertyChanged;
    }
}

Вы также можете написать свой сервис следующим образом:

public class NetworkStatusService
{
    public NetwStatus NetwStat { get; private set; }

    public event EventHandler? NetworkStatusChanged;

    protected virtual void NotifyStatusChanged()
    {
        NetworkStatusChanged?.Invoke(this, EventArgs.Empty);
    }

    public async Task CheckNetw()
    {
        this.NetwStat = NetwStatus.Loading;
        this.NotifyStatusChanged();

        await Task.Delay(1000);

        this.NetwStat = NetwStatus.Fail;
        this.NotifyStatusChanged();
    }
}

Идеальный ответ, спасибо! для тех, кто в будущем задастся вопросом, что именно им следует добавить, не копаясь в моем коде, посмотрите только на методы OnInitialized и Dispose. также во многих случаях вам лучше использовать «защищенное переопределение асинхронной задачи OnInitializedAsync()».

ParSa 12.08.2024 12:05

Другие вопросы по теме

Есть ли способ обновить только объект DI (сервер Blazor)
Как я могу вызвать StateHasChanged() или обновить свой пользовательский интерфейс из реализованного интерфейса на странице .net Blazor .RAZOR?
Как сравнить два изображения, чтобы узнать, являются ли они одним и тем же изображением, используя C# и jquery?
Blazor EditForm: кнопка отключения приводит к тому, что все нетронутые поля помечаются как недействительные
Как добавить несколько веб-приложений Blazor в существующий веб-API
Веб-приложение .Net 8 Blazor (сервер) -> Начните с языка браузера и разрешите пользователю менять язык через раскрывающийся список
Список таблиц не обновляется внутри асинхронного таймера
GraphAPI — запрос имен пользователей, имеющих определенную роль приложения
Blazor .NET 8 — InputSelect: создание раскрывающегося списка из моделей
Мне не хватает импорта ActivatorContent в Blazor (размещенный WASM с использованием .NET 6)?

Похожие вопросы

Azure Document Intelligence — RequestFailedException: «Ресурс не найден, состояние: 404 (не найдено)»
Триггер очереди Azure с настраиваемым именем подключения
Ошибка «Невозможно неявно преобразовать тип» только в том случае, если универсальный экземпляр создается с помощью интерфейса
Как воспроизвести поведение сопоставления шаблонов в операторе переключения C# 4? Функция «сопоставление шаблонов» недоступна в C# 4
Игнорировать всю строку, если преобразование не удалось
Есть ли способ получить сложный объект из строки запроса в ASP.NET Core 8?
Имитация менеджера пользователей с использованием модульного теста ASP.NET Core
EF Core — невозможно выполнить агрегатную функцию для выражения, содержащего агрегат или подзапрос
Почему обязательные поля не учитываются в моей схеме JSON?
Числа, встречающиеся дважды в одном и том же столбце и строке в программе доски судоку