ita*_*sso 18 wpf visibility mediaelement mvvm
我知道ViewModel不应该具有View的任何知识,但我如何从ViewModel调用MediaElement.Play()方法,而不是在ViewModel中引用View(或直接引用MediaElement)?
其他(链接)问题:如何在不违反MVVM模式的情况下从ViewModel管理View的控件可见性?
ken*_*n2k 25
1)不要Play()从视图模型中调用.改为在视图模型中引发事件(例如PlayRequested)并在视图中监听此事件:
查看模型:
public event EventHandler PlayRequested;
...
if (this.PlayRequested != null)
{
this.PlayRequested(this, EventArgs.Empty);
}
Run Code Online (Sandbox Code Playgroud)
视图:
ViewModel vm = new ViewModel();
this.DataContext = vm;
vm.PlayRequested += (sender, e) =>
{
this.myMediaElement.Play();
};
Run Code Online (Sandbox Code Playgroud)
2)您可以在视图模型中公开一个公共布尔属性,并将Visibility控件的属性绑定到此属性.由于Visibility类型Visibility而不是bool,您将不得不使用转换器.
您可以在此处找到此类转换器的基本实现.这个相关问题也可能对您有所帮助.
小智 12
对于所有后来者来说,
有很多方法可以实现相同的结果,它实际上取决于你希望如何实现你的结果,只要你的代码不难维护,我相信在某些情况下打破MVVM模式是可以的.
但话虽如此,我也相信在这种模式中始终有这样做的方式,以下是其中之一,以防万一有人想知道其他替代方案是否可用.
任务:
- 我们不希望从ViewModel直接引用任何UI元素,即MediaElement和View本身.
- 我们想在这里使用Command来做魔术
解决方案:
简而言之,我们将介绍View和ViewModel之间的接口以打破依赖性,View将实现接口并负责直接控制MediaElement,同时让ViewModel只与接口通信,如果需要,可以与其他实现交换以进行测试,这里有长版本:
引入一个名为IMediaService的接口,如下所示:
public interface IMediaService
{
void Play();
void Pause();
void Stop();
void Rewind();
void FastForward();
}
Run Code Online (Sandbox Code Playgroud)在视图中实现IMediaService:
public partial class DemoView : UserControl, IMediaService
{
public DemoView()
{
InitializeComponent();
}
void IMediaService.FastForward()
{
this.MediaPlayer.Position += TimeSpan.FromSeconds(10);
}
void IMediaService.Pause()
{
this.MediaPlayer.Pause();
}
void IMediaService.Play()
{
this.MediaPlayer.Play();
}
void IMediaService.Rewind()
{
this.MediaPlayer.Position -= TimeSpan.FromSeconds(10);
}
void IMediaService.Stop()
{
this.MediaPlayer.Stop();
}
}
Run Code Online (Sandbox Code Playgroud)然后我们在DemoView.XAML中做一些事情:
Run Code Online (Sandbox Code Playgroud)<MediaElement Source="{Binding CurrentMedia}" x:Name="MediaPlayer"/>
Run Code Online (Sandbox Code Playgroud)<UserControl x:Class="Test.DemoView" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ia="http://schemas.microsoft.com/expression/2010/interactivity" x:Name="MediaService">
Run Code Online (Sandbox Code Playgroud)<ia:Interaction.Triggers> <ia:EventTrigger EventName="Loaded"> <ia:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=MediaService}"></ia:InvokeCommandAction> </ia:EventTrigger> </ia:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)<Button Command="{Binding PlayCommand}" Content="Play"></Button> <Button Command="{Binding PauseCommand}" Content="Pause"></Button> <Button Command="{Binding StopCommand}" Content="Stop"></Button> <Button Command="{Binding RewindCommand}" Content="Rewind"></Button> <Button Command="{Binding FastForwardCommand}" Content="FastForward"></Button>
我们现在可以捕获ViewModel中的所有内容(我在这里使用prism的DelegateCommand):
public class AboutUsViewModel : SkinTalkViewModelBase, IConfirmNavigationRequest
{
public IMediaService {get; private set;}
private DelegateCommand<IMediaService> loadedCommand;
public DelegateCommand<IMediaService> LoadedCommand
{
get
{
if (this.loadedCommand == null)
{
this.loadedCommand = new DelegateCommand<IMediaService>((mediaService) =>
{
this.MediaService = mediaService;
});
}
return loadedCommand;
}
}
private DelegateCommand playCommand;
public DelegateCommand PlayCommand
{
get
{
if (this.playCommand == null)
{
this.playCommand = new DelegateCommand(() =>
{
this.MediaService.Play();
});
}
return playCommand;
}
}
.
. // other commands are not listed, but you get the idea
.
}
Run Code Online (Sandbox Code Playgroud)附注:我使用Prism的自动连线功能来链接View和ViewModel.所以在View的代码隐藏文件中没有DataContext赋值代码,我更喜欢保持这种方式,因此我选择使用纯命令来实现这个结果.
| 归档时间: |
|
| 查看次数: |
8673 次 |
| 最近记录: |