XAML и MVVM в приложении UWP с интеграцией SignalRC#

Место общения программистов C#
Ответить
Anonymous
 XAML и MVVM в приложении UWP с интеграцией SignalR

Сообщение Anonymous »

Я пытаюсь определить, правильно ли я делаю это. Вот поток данных, который я имел настройки с MVVM в приложении UWP: < /p>
view viewmodel model < /p>
Я написал сигналрр Клиент, который передается конструктору модели при инициализации. Каждый экземпляр модели устройства имеет клиент SignalR, который позволяет серверу SignalR вызовать методы на всех подключенных устройствах. Вот проблема: < /p>
Когда сервер SignalR вызывает метод на устройстве, он делает это с зарегистрированным обратным вызовом в модели. Нет проблем, этот обратный вызов устанавливает свойство, а модель наследует от ObservableObject от communitytoolkit.mvvm.componentmodel , чтобы он мог обновить ViewModel и так далее, пока пользовательский интерфейс не покажет изменение.
Теперь нам нужно пойти в другую сторону. Просмотр обновляется, ViewModel также наследуется от ObservableObject , свойство ViewModel изменяется путем просмотра из -за двухстороннего x: bind на элементе, модель подписывает на PropertyChanged Событие ViewModel, а модель получает Обновленное значение, а затем может вызвать правильный метод Invoke в экземпляре клиента SignalR, чтобы вызвать удаленный метод на сервере. Оба направления? Я имею в виду, когда изменяется свойство модели, то ViewModel будет запустить событие PropertyChanged . В то время как обновленное значение находится на пути к представлению с помощью привязки, разве событие Property Code>, которое модель подписана, также запускается? Что тогда приведет к тому, что такое же значение, которое клиент SignalR только что получил от сервера, который будет отправлен обратно на сервер, чтобы быть обновленным с помощью значения, которое он уже получил? Как это не вызывает рекурсивную петлю обратной связи между обработчиками событий? Даже просто между моделью и ViewModel? Использование только событий PropertyChanged в ViewModel и Model не кажется правильным. < /p>

< /code>
-код, содержит: < /p>
using Microsoft.Extensions.DependencyInjection;
using MyProj.ViewModels;
using Windows.UI.Xaml.Controls;

namespace MyProj.Views
{
public sealed partial class ScenarioEnvConfig : UserControl
{
private readonly ScenarioEnvConfigVm _vm;

public ScenarioEnvConfig()
{
this.InitializeComponent();
_vm = (ScenarioEnvConfigVm)App.Current.Services.GetRequiredService(typeof(ScenarioEnvConfigVm));
}
}
}
< /code>
ViewModel содержит: < /p>
using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.ComponentModel;
using MyProj.Models;
using MyProj.Services;
using Windows.UI.Core;

namespace MyProj.ViewModels
{
public class ScenarioEnvConfigVm : ObservableObject
{
private NetDevice _netDevice;

private int _audioVolume;
public int AudioVolume
{
get => _audioVolume;
set
{
// This will propegate view changes back to model
SetProperty(ref _audioVolume, value);
// If I try to update SignalRServer here, it gets
// called when updates come from network or view
// causing server to receive and propagate to all
// clients, unnecessary update, which they will all
// do again, in turn, creating the storm.
if (_netDevice != null)
_netDevice.AudioVolume = value;
}
}

public ScenarioEnvConfigVm(NetDevice netDev)
{
_netDevice = netDev;
_netDevice.PropertyChanged += new
PropertyChangedEventHandler(OnNetDevPropertyChanged);
}

private async void OnNetDevPropertyChanged(object sender,
PropertyChangedEventArgs e)
{
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
if (e.PropertyName == "AudioVolume")
AudioVolume = _netDevice.AudioVolume;
});
}

}
}
< /code>
Модель содержит: < /p>
using CommunityToolkit.Mvvm.ComponentModel;
using System.Collections.ObjectModel;
using MyProj.OpenAPIs;
using MyProj.Services;

namespace MyProj.Models
{
public class NetDevice : ObservableObject
{
private readonly SignalRClient _srClient;

private int _audioVolume = 0;
public int AudioVolume
{
get => _audioVolume;
// If I try to update SignalRServer here, it gets
// called when updates come from network or view.
set => SetProperty(ref _audioVolume, value);
}

public NetDevice(SignalRClient srClient)
{
_srClient = srClient;
_srClient.OnVolumeChanged += OnAudioVolumeChanged;
_ = _srClient.ConnectAsync();
}

private void OnAudioVolumeChanged(int volume)
{
AudioVolume = volume;
// I am thinking this should look more like:
// _audioVolume = volume;
// PropertyChanged?.Invoke(volume);
// With this change, I *should* be able to freely
// make the network call in the setter above
// and trust that it came from the view/viewmodel.
// and know that signalr server will not get another
// update request from a client it just updated.
}
}
}
< /code>
Это отлично подходит для получения изменений модели от сети в представление. Мне нужно получить изменения в представлении обратно на устройство и по сети. Если я вызовут метод InvokeAsync на сигнале, который мне нужен в ViewModel, или в «сеттере» свойства модели, он будет вызван в любое время, когда том обновляется из сети. Это цикл обратной связи, о котором я говорил. Полем Это в основном ситуация общего состояния. , Я могу выполнить метод сервера SignalR, необходимый для его изменения на самом устройстве, и при этом обновлять представление в любое время, когда службы сетевой интеграции также обновляют его. Даже попытаться это не обновлять свойство AudioVolume в обратном вызове NetDevice SignalRClient и вместо этого обновить только частную переменную поддержки, а затем вручную поднять событие, измененное свойство в этом обратном вызове, чтобы ViewModel мог получить доступ к Getter для этого свойства и PropeGate это в представление с помощью привязки данных TwoWay. .Invokeasync Метод обновления фактического аппаратного устройства. Это хороший способ решить эту проблему?

Подробнее здесь: https://stackoverflow.com/questions/794 ... ntegration
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»