使用 MVVM,如何在低级服务和视图模型之间建立通信线路?
Posted
技术标签:
【中文标题】使用 MVVM,如何在低级服务和视图模型之间建立通信线路?【英文标题】:Using MVVM, how can I establish a line of communication between a low level service and view model? 【发布时间】:2018-07-17 06:01:40 【问题描述】:我正在使用 Prism 和 Unity 实现具有蓝牙连接的媒体播放器应用程序。
我正在使用的应用程序流程如下:
-
用户在远程设备(手机/平板电脑)上发出命令
桌面应用程序通过蓝牙服务接收
Play
命令
更高级别的服务处理元数据并告诉VideoPlaybackViewModel
开始播放
到目前为止我所拥有的
蓝牙服务还没有实现,因为我想先完成其他元素。当谈到 是时候这样做了,我会按照这个例子(https://github.com/saramgsilva/BluetoothSampleUsing32feet.Net)。
按照这个问题(MVVM pattern violation: MediaElement.Play()),
我已经实现了VideoPlaybackView
和VideoPlaybackViewModel
。
VideoPlaybackView
:
<UserControl x:Class="Views.VideoPlaybackView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ia="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
x:Name="MediaService">
<ia:Interaction.Triggers>
<ia:EventTrigger EventName="Loaded">
<ia:InvokeCommandAction Command="Binding LoadedCommand" CommandParameter="Binding ElementName=MediaService" />
</ia:EventTrigger>
</ia:Interaction.Triggers>
<Grid>
<MediaElement
x:Name="VideoPlayer"
Source="Binding VideoSource" />
</Grid>
</UserControl>
VideoPlaybackViewModel
:
public class VideoPlaybackViewModel : BindableBase
private Uri _videoSource;
public IMediaService MediaService get; private set;
public Uri VideoSource
get => _videoSource;
set => SetProperty(ref _videoSource, value);
private DelegateCommand<IMediaService> _loadedCommand;
public DelegateCommand<IMediaService> LoadedCommand
get
if (_loadedCommand == null)
_loadedCommand =
new DelegateCommand<IMediaService>((mediaService) => MediaService = mediaService; );
return _loadedCommand;
这些在加载VideoPlaybackModule
时被初始化:
public class VideoPlaybackModule : IModule
private IUnityContainer _container;
private IRegionManager _regionManager;
public VideoPlaybackModule(IUnityContainer container, IRegionManager regionManager)
_container = container;
_regionManager = regionManager;
public void Initialize()
_regionManager.RegisterViewWithRegion("MainRegion", typeof(VideoPlaybackView));
我使用模块是因为我想学习它们。
目标
我想要的是有一个可以从蓝牙服务接收事件的控制器,
解析元数据,更新MediaElement.Source
,并以某种方式向VideoPlayerViewModel
发送命令
实际播放视频。
尝试
我已经看到了实现控制器的想法,但我不确定我应该如何初始化它。我上来
有以下问题:
- 如何连接控制器以响应来自蓝牙服务的蓝牙命令?
- 控制器是否应该保留对VideoPlaybackViewModel
的引用以执行命令?
我认为这里也可以应用一项服务。例如,如果我创建了一个VideoPlaybackService
,该服务将如何使用?类似于控制器的想法,它需要在向VideoPlayerViewModel
发送命令之前处理元数据的处理。
如何使用 Prism 和 Unity 来实现这种模式?
【问题讨论】:
【参考方案1】:有很多方法可以做到这一点,但似乎 Mediator Pattern 可能是您正在寻找的机器人。这将有助于减少您担心的耦合
Mediator pattern
使用中介者模式,对象之间的通信是 封装在中介对象中。对象不再通信 直接相互交流,而是通过 调解人。这减少了通信对象之间的依赖关系, 从而减少耦合。
Coupling
在软件工程中,耦合是相互依赖的程度 软件模块之间;衡量两个人的联系程度 例程或模块是;之间关系的强度 模块。
在类似 MVVM Light 中,您可以使用 MVVM Light Messenger。
它有点像Pub/Sub 事件,当您注册/订阅消息时,您的解耦类可以发布/发送 说的消息。
不过,既然您提到您使用的是Prism,您可以使用EventAggregator
。这又是一种 Pub/Sub 安排。
从您的服务发送事件的示例
this.eventAggregator
.GetEvent<PubSubEvent<BlueToothData>>()
.Publish(new BlueToothData SomeData = someData );
ViewModel 中的接收和事件示例
var subscriptionToken = this.eventAggregator
.GetEvent<PubSubEvent<BlueToothData>>()
.Subscribe((details) =>
// what ever you want to do here;
);
注意:我不使用 Prism,但是 EventAggregator 有大量可用资源
其他资源
Prism Event Aggregator in WPF With MVVM
Using the Event Aggregator Pattern to Communicate
【讨论】:
感谢您的回答。考虑到我的问题,我认为这是最好的方法。我想知道随着应用程序复杂性的增加,这是否仍然可以使用。我会把这个想法留到以后。以上是关于使用 MVVM,如何在低级服务和视图模型之间建立通信线路?的主要内容,如果未能解决你的问题,请参考以下文章