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 На элементе модель обновляется ViewModel, установив свойство модели общего аудидиовума. Он получает обновленное значение и может затем вызвать правильный метод Invoke в экземпляре клиента SignalR, чтобы вызвать удаленный метод на сервере. События, выпускающие оба направления? Использование только событий PropertyChanged в ViewModel для обновления модели так же, как многие статьи и стека* Q & A Предлагают, что это не достаточно.
Просмотр содержит: < /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
{
SetProperty(ref _audioVolume, value);
// This next statement will propegate view changes
// to the model.
// 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.
// However, the slider goes crazy when I do this.
// Is this a cancellation token problem? Do I need
// to cancel update operations that are in-flight
// as two-way slider events are being processed so
// that prior update operations can be cancelled
// until a final value is settled upon?
}
}
}
< /code>
Это отлично подходит для получения изменений модели от сети в представление. Мне нужно получить изменения в представлении обратно на устройство и по сети. Если я вызовут метод InvokeAsync на сигнале, который мне нужен в ViewModel, или в «сеттере» свойства модели, он будет вызван в любое время, когда том обновляется из сети. Это цикл обратной связи, о котором я говорил. Полем Это в основном ситуация общего состояния. , Я могу выполнить метод сервера SignalR, необходимый для его изменения на самом устройстве, и при этом обновлять представление в любое время, когда службы сетевой интеграции также обновляют его. Даже попытаться это не обновлять свойство AudioVolume в обратном вызове NetDevice SignalRClient и вместо этого обновить только частную переменную поддержки, а затем вручную поднять событие, измененное свойство в этом обратном вызове, чтобы ViewModel мог получить доступ к Getter для этого свойства и PropeGate это в представление с помощью привязки данных TwoWay. .Invokeasync Метод обновления фактического аппаратного устройства. Это хороший способ решить эту проблему? Потому что, когда я делаю это таким образом, и как показывают комментарии выше, это идет плохо. < /P>
Вот фотография фактического виджета. И да, когда я внедряю вышеуказанную стратегию, а обновления появляются из сети, без проблем. Когда используется слайдер, он сходит с ума, и до тех пор, пока приложение работает, он подпрыгивает повсюду между первоначальным значением и значением назначения, как происходит обратная связь «шторм», описанная выше. Я был чертовски осторожен и до сих пор не могу понять это поведение. По сути, я пытаюсь установить привязку к двум плаванию между слоем интеграции сети системной архитектуры. i.sstatic.net/51uquyph.png "/>

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

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

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

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

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

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