Я зарегистрировал службу в 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()
но он НИКОГДА не переходит в режим «Пытаюсь подключиться...». он просто ждет и меняется либо на успех, либо на неудачу. Это очень расстраивает, я начинаю ненавидеть свою карьеру.
@Дай, это очень расстраивает, оно полностью работало как локальное свойство в моей ViewModel, но перестало работать после того, как я переместил его в сервис... заставляет меня ненавидеть .net, они по какой-то причине превращают каждую простую задачу в головную боль
Я понимаю, что это расстраивает, но вы не ответили на мои вопросы...
@Dai Я попробую отладить это завтра на работе и сообщу вам как можно скорее, спасибо, что заметили это
@Dai хаха ты ответил мне так быстро, что я едва успел напечатать второй комментарий





Именно поэтому я считаю, что INotifyPropertyChanged не так хорошо работает с Blazor. Эта строка эквивалентна async void:
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
Поскольку вы не ожидаете (и не можете) этого, рендеринг отключается от потока программы.
В OnPropertyChanged() вам придется вызвать StateHasChanged(), но это защищенный метод страницы. Это означает, что вам понадобится какая-то уродливая связь IView для передачи ViewModel. И сантехника для этого.
ох чувак, ты сказал мое сердце, разве они не должны это просто исправить? так много ненужных сложностей в Блазоре/Мауи. изменил свой код тысячей способов и остался на работе еще на 4 часа сегодня только для того, чтобы завтра услышать «ты отстаешь». Вероятно, мне следует начать переходить на что-то другое, кроме .net.
Что ж, сначала рассмотрите возможность использования Blazor без MVVM или, по крайней мере, без INotifyPropertyChanged. Обратите внимание: я никогда не использовал Blazor/MAUI, но знаю WPF и XAML. Blazor — это другая платформа с более простой привязкой к данным и событиям. Меньше абстракций, но очень полезно. Плывите по течению.
Ну, не идеально, но я добавил это на свою страницу OnInitializeAsync:
NetworkStatusService.PropertyChanged += (sender, args) => InvokeAsync(StateHasChanged);
и это работает.
Это относительно простой обходной путь, я предполагал нечто гораздо большее.
Я отвечал на этот вопрос, пока вы опубликовали этот ответ. Смотрите мой ответ, как правильно реализовать это с помощью IDisposable, чтобы удалить обработчик при уничтожении компонента.
@MrCakaShaunCurtis, спасибо! именно так и надо делать.
Вам нужно подключить компонент к событию 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()».
...использовали ли вы пошаговый отладчик для исследования проблемы? Если да, то расскажите, пожалуйста, что именно произошло внутри
OnPropertyChanged? Если нет, то почему?