使用 MVVM,如何在低级服务和视图模型之间建立通信线路?

Using MVVM, how can I establish a line of communication between a low level service and view model?

我正在使用 Prism 和 Unity 实现具有蓝牙连接功能的媒体播放器应用程序。

我正在使用的应用程序流程如下:

  1. 用户在远程设备上发出命令(phone/tablet)
  2. 桌面应用程序通过蓝牙服务接收 Play 命令
  3. 更高级别的服务处理元数据并通知 VideoPlaybackViewModel 开始播放

到目前为止我有什么

蓝牙服务还没有实现,因为我想先完成其他元素。当谈到 是时候这样做了,我将按照这个例子 (https://github.com/saramgsilva/BluetoothSampleUsing32feet.Net)。

根据这个问题 (MVVM pattern violation: MediaElement.Play()), 我已经实现了 VideoPlaybackViewVideoPlaybackViewModel.

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,该服务将如何使用?和controller的思路类似,在向VideoPlayerViewModel.

发送命令之前,需要处理元数据

如何使用 Prism 和 Unity 实现此模式?

有很多方法可以做到这一点,但 中介模式 似乎就是您正在寻找的机器人。这将有助于减少您所关心的耦合

Mediator pattern

With the mediator pattern, communication between objects is encapsulated within a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator. This reduces the dependencies between communicating objects, thereby reducing coupling.

Coupling

In software engineering, coupling is the degree of interdependence between software modules; a measure of how closely connected two routines or modules are; the strength of the relationships between modules.

在类似 MVVM Light 的情况下,您可以使用 MVVM Light Messenger.

这有点像 Pub/Sub 事件,当你 Register/Subscribe 发了一条消息,你的 解耦了 class可以Publish/Send表示留言。

但是既然你提到你正在使用 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