如何将流从 ViewModel 发送到 XAML 页面上的 MediaElement?

Posted

技术标签:

【中文标题】如何将流从 ViewModel 发送到 XAML 页面上的 MediaElement?【英文标题】:How to send stream from ViewModel to the MediaElement on the XAML page? 【发布时间】:2016-10-19 14:40:06 【问题描述】:

只需将 ViewModel(继承自 MVVM Light ViewModelBase)中的文本字符串朗读到 XAML 页面上的 MediaElement

var synthesisStream = await synthesizer.SynthesizeSsmlToStreamAsync(text);
media.AutoPlay = true;
media.SetSource(synthesisStream, synthesisStream.ContentType);
media.Play();

上面的代码没有分离ViewModel。我们看到media 直接在代码隐藏中处理。

在我的 ViewModel 中,我停在了

var synthesisStream = await synthesizer.SynthesizeSsmlToStreamAsync(text);

var msg=new PlaySpeechSynthesisStreamMessage(synthesisStream);
Messenger.Default.Send<PlaySpeechSynthesisStreamMessage>(msg);

对于消息:

public class PlaySpeechSynthesisStreamMessage

    public SpeechSynthesisStream Stream  get; set; 

    public PlaySpeechSynthesisStreamMessage(SpeechSynthesisStream stream)
    
        Stream = stream;
    

Messenger 是处理这种情况的正确方法吗?我们如何编写RelayCommand 或其他东西来将流传递给media

一篇相关文章MVVM pattern violation: MediaElement.Play() 似乎解决了这个问题,但它不在 MVVM Light 中,也没有办法通过流。

【问题讨论】:

【参考方案1】:

我认为消息是处理这种情况的好方法。 您只需要在 ViewModel 中对消息的发送进行补充,并在 View 中对其进行处理:

Messenger.Default.Register<PlaySpeechSynthesisStreamMessage>(this, msg => 
    media.AutoPlay = true;
    media.SetSource(msg.Stream, msg.Stream.ContentType);
    media.Play();
);

或者,您可以使用您引用的问题中描述的事件方法。在这种情况下,您必须定义一个继承自 EventArgs 的类,其属性类型为 SpeechSynthesisStream,然后按如下方式定义您的事件:

public event EventHandler<YourEventArgsClass> PlaySpeechSynthesisStreamEvent;

并以这种方式提升它:

var synthesisStream = await synthesizer.SynthesizeSsmlToStreamAsync(text);
var eventArgs = new YourEventArgsClass(synthesisStream);
if (PlaySpeechSynthesisStreamEvent != null)
    PlaySpeechSynthesisStreamEvent(this, eventArgs);

当然,在这种情况下,您必须在视图中处理事件。

我发现使用事件处理程序的解决方案比使用消息的解决方案要复杂一些,因为您必须将事件处理连接到视图的 DataContext,并且根据应用程序的结构,DataContext 属性View 在 View 生命周期开始时并不总是可用:例如,在许多情况下,我倾向于在导航到视图期间通过 Navigation Service 和/或 Bootstrapper 设置它:在这种情况下,DataContext 在View 的 costructor,因此不可能在那里连接事件处理程序。因此,您必须找到另一个连接它的地方,记住 OnNavigatedFrom 等方法(例如,在 Windows 10 UWP 应用程序中)可以在视图的生命周期中多次调用,当然我们不想连接事件处理程序不止一次。 如果框架公开它(例如在 Windows 10 UWP 中),DataContextChanged 事件可能是连接与 ViewModel 相关的事件处理程序的好地方(如果 View 的实例可以与不同的实例一起使用,则可能删除以前的事件处理程序)应用程序生命周期内的 ViewModel 类)。

【讨论】:

以上是关于如何将流从 ViewModel 发送到 XAML 页面上的 MediaElement?的主要内容,如果未能解决你的问题,请参考以下文章

如何将音频流从输出设备发送到输入设备?

如何在 android 上播放 webrtc.AudioTrack(无视频)

如何使用 DataContext 属性在 XAML 中的窗口上设置 ViewModel?

TreeView ItemSsource 绑定到 ViewModel 不更新 xaml 控件项

将 WPF xaml 绑定到 ViewModel 而不构造它

如何在 ViewModel 中获取控件的高度