В настоящее время я пишу небольшой веб-интерфейс Blazor. Я пытаюсь внедрить / реализовать шаблон MVVM. Для этого я создал два базовых класса компонентов. Один, который просто обрабатывает методы жизненного цикла Blazor (добавляет некоторую обработку исключений), а другой обрабатывает инициализацию ViewModel на основе выполнения этих методов жизненного цикла. Компонент также реализует интерфейс IDisposable, который автоматически вызывается Blazor, когда компонент становится невидимым.
Вот фрагмент кода из моего класса WebComponentBase и класса ViewModelAwareComponent, чтобы примерно дать представление о шаблоне:
public abstract class WebFpComponentBase : ComponentBase, IDisposable, IHtmlStyles
{
private const string DEFAULT_DIM_VALUE = "auto";
[Inject]
protected IExceptionUiHandler<ErrorRedirectViewModel> ExceptionUiHandler { get; set; }
//fields and parameters omitted for brevity
#region Blazor Component LifeCycle
/// <summary>
/// OnInitialized is called after OnInitialized, when the component has received all initial parameters. Place any asynchronous operations here,
/// which require the component to re-render.
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
try
{
await base.OnInitializedAsync();
_logger.Info($"{nameof(OnInitializedAsync)} - method invoked in component of type ${this.GetType().FullName}");
await OnInitializedInternalAsync();
_logger.Info($"{nameof(OnInitializedAsync)} - method finished in component of type ${this.GetType().FullName}");
} catch(Exception ex)
{
//Exception, if any happend, is forwared using the IExceptionUiHandler in the AfterRenderAsync() method
_forwardException = ex;
_logger.Error($"{nameof(OnInitializedAsync)}: Catching and forwarding exception of type {_forwardException.GetType().FullName}");
}
}
protected abstract Task OnInitializedInternalAsync();
//other methods of the class omitted for brevity
}
Затем мой ViewModelAwareComponent, у которого есть свойство, содержащее ViewModel, и который автоматически запускает инициализацию и деинициализацию ViewModel (закрытие любых соединений службы, сброс любых значений и т. Д.) Путем реализации внутренних абстрактных методов [BlazorLifecycleMethod].
public abstract class ViewModelAwareComponent<TViewModel> : WebFpComponentBase where TViewModel : BaseViewModel
{
private Logger _logger = LogManager.GetCurrentClassLogger();
[Parameter]
public virtual TViewModel ViewModel { get; set; }
protected override async Task OnInitializedInternalAsync()
{
await ViewModel.InitializeAsync();
ViewModel.PropertyChanged += this.FireComponentStateHasChanged;
}
public override async void Dispose()
{
base.Dispose();
await ViewModel.DeactivateAsync();
}
protected virtual async void FireComponentStateHasChanged(object sender, PropertyChangedEventArgs e)
{
_logger.Trace($"FireComponentStateHasChanged: property {e.PropertyName} has changed!");
await InvokeAsync(this.StateHasChanged);
}
protected override async Task OnParametersSetAsyncInternal()
{
if (ViewModel == null)
{
throw new ArgumentNullException($"{nameof(ViewModel)}", "Parameter must be supplied!");
}
}
}
BaseViewModel-Type реализует INotifyPropertyChanged только обычным образом. У меня есть «MainViewModel», который должен быть создан только один раз для всего соединения (схема Blazor). Поэтому я добавил его через services.AddScoped()
в Startup.cs
. Поскольку он не привязан к какому-либо конкретному компоненту, я вставляю его в свой MainLayout.razor
, который является макетом для каждого компонента Razor, который я написал.
Макет реализует protected override async Task OnInitializedAsync()
, как указано ниже:
protected override async Task OnInitializedAsync()
{
MainViewModel.PropertyChanged += (obj, args) => InvokeAsync(StateHasChanged);
await MainViewModel.InitializeAsync();
//some other stuff happening afterwards
}
Моя проблема сейчас в том, что инициализация и выполняется дважды при каждом запуске приложения, а не только один раз за соединение. То же самое верно и для деинициализации, потому что Dispose () компонента вызывается также дважды.
При отладке я заметил, что OnInitializedAsync
не вызывается повторно при переключении между двумя моими существующими страницами (маршрутизируемыми компонентами). Он вызывается только дважды при запуске.
Может быть, у вас есть предложения по этому поводу? Есть ли лучший способ добиться желаемого поведения для MainViewModel?
С уважением,
наклон
await MainViewModel.InitializeAsync();
в макетеOnInitializedAsync
? - person agua from mars   schedule 26.09.2019MainViewModel
- этоComponentBase
, верно? Итак, при рендеринге вызывается метод InitializeAsync. ИМХО, не надо это называть. - person agua from mars   schedule 27.09.2019