ViewModel 中的 MediaElement.play()

Posted

技术标签:

【中文标题】ViewModel 中的 MediaElement.play()【英文标题】:MediaElement.play() from within ViewModel 【发布时间】:2014-05-01 14:42:30 【问题描述】:

我正在努力解决以下问题:

我正在使用 MVVM 模式构建一个 WP8 应用程序。我的 view.xaml 中有一个媒体元素,并且在我的 viewmodel.cs 中有控制这个媒体元素的逻辑(例如,播放、停止、暂停和音量)。

如何使用绑定从我的视图模型中在此媒体元素上播放声音。在不破坏 MvvM 的目的和结构的情况下。

(PS:我看过下面的帖子,但不知道如何实现?Link to post)

【问题讨论】:

你从上面的链接有什么不明白的? 如何实现事件处理程序。似乎缺少部分代码? ……应该放什么? 不行,你可以试试同样的代码,如果有错误可以发帖! 就是这个地方,vm.PlayRequested += (sender, e) => this.myMediaElement.Play(); ; 那么,如果我想在我的视图模型中替换 MediaElement.play,我该如何替换该调用以便我视图中的 Playrequested 触发? 【参考方案1】:

您可以直接从视图模型绑定媒体元素

在 xaml 中:

<ContentControl Content="Binding MediaElementObject"/>

在 ViewModel 中:

private MediaElement _mediaElementObject;

public MediaElement MediaElementObject

   get  return _mediaElementObject; 
   set  _mediaElementObject = value;RaisePropertyChanged(); 

OnNavigatedTo Override 方法上,您可以创建它的新对象并注册它的事件。

MediaElementObject=new MediaElement();

这样您就可以从视图模型本身做所有事情。

【讨论】:

最佳答案 Asitis .. :) 我可以 100% 验证这个工作,我强烈建议使用这个解决方案。对于所有具有相同问题的少数其他控件的讨厌,这是一个很好的思路,它需要在 mediaElement 的内部道具和您的 VM 设计用于暴露给视图的那些非常容易实现的道具之间进行一些管道连接。谢谢 asitis。 我同意这会起作用,但绝对不推荐这样做。你不应该在你的 ViewModel 上有 UI 元素。如果您想在 Xamarin 上使用相同的 ViewModel 怎么办(我们那里没有 MediaElement),如果您使用单元测试怎么办? ViewModel 不应该知道MediaElement。这违反了 MVVM 的原则。答案错误。【参考方案2】:

上面的答案在 ViewModel 中使用了MediaElement。此元素是 VM 应保持不可知的视图端组件。

实现这一点的一种方法是通过公开该事件的接口在 ViewModel 中公开一个事件,然后让视图通过运行其MediaElement、通过代码隐藏或使用交互触发器来响应该事件。

视图模型:

public interface ISoundPlayer

  event Action Play();
    

public class MyViewModel : ViewModelBase, ISoundPlayer

  public event Action Play;

查看:

public class MyView : UserControl

  ISoundPlayer _SoundPlayer;

  public MyView()
  
    DataContextChanged += OnDataContextChanged;
    Unloaded += OnUnloaded;
    

  void OnDataContextChanged(DependencyObject sender, DataContextChangedEventArgs args)
  
    if (DataContext is ISoundPlayer player && _SoundPlayer != player)
    
      if (_SoundPlayer != null)
        _SoundPlayer.Play -= OnPlay;

      _SoundPlayer = player;
      _SoundPlayer.Play += OnPlay;
        
  

  void OnUnloaded(object sender, RoutedEventArgs e)
  
    if (_SoundPlayer != null)
      _Metronome.Play -= OnPlay;
  

  void OnPlay() => myMediaElement.Play();

【讨论】:

【参考方案3】:

asitis的答案很好。我给你看我的详细代码:(使用caliburn.micro所以不需要绑定名称)

查看

    <Grid>
         <ContentControl Content="Binding MediaElementObject"/>
    </Grid>

    <StackPanel Orientation="Horizontal">
         <Button x:Name="ButtonPlay" Content="Play" Width="220px" Margin="20,5"/>
         <Button x:Name="ButtonStop" Content="Stop" Width="220px" Margin="20,5"/>
         <Button x:Name="ButtonForward" Content="Forward(30s)" Width="220px" Margin="20,5"/>
         <Button x:Name="ButtonBack" Content="Back(30s)"Width="220px" Margin="20,5"/>
     </StackPanel>

视图模型

    private MediaElement _mediaElementObject = new MediaElement();
    public MediaElement MediaElementObject
    
        get  return _mediaElementObject; 
        set
        
            _mediaElementObject = value;
            NotifyOfPropertyChange(() => MediaElementObject);
        
    

    public void ButtonPlay()
    
        MediaElementObject.Source =new Uri( @"C:\Users\admin\Videos\XXXXXX.wmv");
        MediaElementObject.LoadedBehavior = MediaState.Manual;
        MediaElementObject.UnloadedBehavior = MediaState.Manual;
        MediaElementObject.Play();
         

    public void ButtonStop()
    
        MediaElementObject.Stop();
    
    public void ButtonForward()
    
        MediaElementObject.Position = _mediaElementObject.Position + TimeSpan.FromSeconds(30);
    
    public void ButtonBack()
    
        MediaElementObject.Position = _mediaElementObject.Position - TimeSpan.FromSeconds(30);
    

可能可以帮助某人:)

【讨论】:

以上是关于ViewModel 中的 MediaElement.play()的主要内容,如果未能解决你的问题,请参考以下文章

在 MVVM 中,从 Model 或 ViewModel 播放媒体文件?

WPF中MediaElement的Source问题

WPF中的MediaElement从流中播放视频?

IE 中的 Mediaelement.js 故障,没有闪回工作

Windows UWP 应用程序中的 MediaElement 不播放音频

Mediaelement.js - 想要删除所有控件 - 仅显示视频