C# 如何使用ViewModel优先方法从ViewModel调用视图方法

C# 如何使用ViewModel优先方法从ViewModel调用视图方法,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我正在使用框架开发一个WPF应用程序,其体系结构基于模型-视图-模型-模式原则 以下XAML代码是my View ViewModel关系的示例: <... .Resources> <DataTemplate DataType="{x:Type viewm:MediaElementViewModel}"> <view:MediaElement/> </DataTemplate> </... .Resources>

我正在使用框架开发一个WPF应用程序,其体系结构基于模型-视图-模型-模式原则

以下XAML代码是my View ViewModel关系的示例:

<... .Resources>
   <DataTemplate DataType="{x:Type viewm:MediaElementViewModel}">
       <view:MediaElement/>
   </DataTemplate>
</... .Resources>

我知道,在构造具体的
MediaElement
时,可以通过分配
MediaElement
实例的
DataContext
属性从ViewModel调用视图方法,不幸的是,这不是我的解决方案

例如,视图方法是
MediaElement
,例如
Play()
Pause()
Focuse()
或任何其他“纯”UI方法


非常感谢。

视图引用了您的视图模型,但对其没有内在知识或访问权限

如果您建议的方法是show和close,那么通过绑定到visibility属性的视图模型来处理这个问题就很简单了


其他可能有用的概念是数据触发器,它允许您通过动画行为更新视图、设置属性或从许多条件触发。视图引用了视图模型,但对其没有内在知识或访问权限

如果您建议的方法是show和close,那么通过绑定到visibility属性的视图模型来处理这个问题就很简单了


其他可能有用的概念是数据触发器,它允许您通过动画行为更新视图、设置属性或从许多条件触发。我找到了一个有效的解决方案,我将保留它的答案,直到找到更好的解决方案

解决方案基于定制

需要注意的是,问题和答案在全局范围内,而不是
MediaElement
范围内。因此,此解决方案与支持ViewModel First方法的每个
框架元素
派生控件完全相关

为了清晰起见,我没有删除任何代码。

ViewTemplates.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication2"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <DataTemplate DataType="{x:Type local:MediaElementViewModel}">
        <MediaElement Source="{Binding Source}" Volume="{Binding Volume}"
                        LoadedBehavior="Manual" UnloadedBehavior="Manual">
            <i:Interaction.Behaviors>
                <local:MediaElementBehavior/>
            </i:Interaction.Behaviors>
        </MediaElement>
    </DataTemplate>
</ResourceDictionary>
<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ViewTemplates.xaml"/>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding CurrentMediaElement}"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Set Source" Command="{Binding SetSourceCommand}"/>
        <WrapPanel Grid.Row="1" Grid.Column="2">
            <Button Grid.Row="1" Grid.Column="2" Content="Stop" Command="{Binding StopCommand}"/>
            <Button Content="Focus" Command="{Binding FocusCommand}"/>
        </WrapPanel>

        <Button Grid.Row="1" Grid.Column="1" Content="Play" Command="{Binding PlayCommand}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding CurrentMediaElement.Source}" TextWrapping="Wrap"/>
        <Label Grid.Row="2" Grid.Column="1" Content="{Binding ElementName=SliderVolume, Path=Value}"/>
        <Slider x:Name="SliderVolume" Value="{Binding CurrentMediaElement.Volume}" Grid.Row="2" Grid.Column="2" Minimum="0" Maximum="1" Orientation="Horizontal"/>
    </Grid>
</Window>
以下是上述解决方案使用的示例:

App.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication2"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <DataTemplate DataType="{x:Type local:MediaElementViewModel}">
        <MediaElement Source="{Binding Source}" Volume="{Binding Volume}"
                        LoadedBehavior="Manual" UnloadedBehavior="Manual">
            <i:Interaction.Behaviors>
                <local:MediaElementBehavior/>
            </i:Interaction.Behaviors>
        </MediaElement>
    </DataTemplate>
</ResourceDictionary>
<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ViewTemplates.xaml"/>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding CurrentMediaElement}"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Set Source" Command="{Binding SetSourceCommand}"/>
        <WrapPanel Grid.Row="1" Grid.Column="2">
            <Button Grid.Row="1" Grid.Column="2" Content="Stop" Command="{Binding StopCommand}"/>
            <Button Content="Focus" Command="{Binding FocusCommand}"/>
        </WrapPanel>

        <Button Grid.Row="1" Grid.Column="1" Content="Play" Command="{Binding PlayCommand}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding CurrentMediaElement.Source}" TextWrapping="Wrap"/>
        <Label Grid.Row="2" Grid.Column="1" Content="{Binding ElementName=SliderVolume, Path=Value}"/>
        <Slider x:Name="SliderVolume" Value="{Binding CurrentMediaElement.Volume}" Grid.Row="2" Grid.Column="2" Minimum="0" Maximum="1" Orientation="Horizontal"/>
    </Grid>
</Window>

main window.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication2"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <DataTemplate DataType="{x:Type local:MediaElementViewModel}">
        <MediaElement Source="{Binding Source}" Volume="{Binding Volume}"
                        LoadedBehavior="Manual" UnloadedBehavior="Manual">
            <i:Interaction.Behaviors>
                <local:MediaElementBehavior/>
            </i:Interaction.Behaviors>
        </MediaElement>
    </DataTemplate>
</ResourceDictionary>
<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ViewTemplates.xaml"/>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding CurrentMediaElement}"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Set Source" Command="{Binding SetSourceCommand}"/>
        <WrapPanel Grid.Row="1" Grid.Column="2">
            <Button Grid.Row="1" Grid.Column="2" Content="Stop" Command="{Binding StopCommand}"/>
            <Button Content="Focus" Command="{Binding FocusCommand}"/>
        </WrapPanel>

        <Button Grid.Row="1" Grid.Column="1" Content="Play" Command="{Binding PlayCommand}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding CurrentMediaElement.Source}" TextWrapping="Wrap"/>
        <Label Grid.Row="2" Grid.Column="1" Content="{Binding ElementName=SliderVolume, Path=Value}"/>
        <Slider x:Name="SliderVolume" Value="{Binding CurrentMediaElement.Volume}" Grid.Row="2" Grid.Column="2" Minimum="0" Maximum="1" Orientation="Horizontal"/>
    </Grid>
</Window>

MainViewModel.cs

public MediaElementViewModel()
{
    Volume = 0.5;
}

private Uri _source;
public Uri Source
{
    get { return _source; }
    set
    {
        _source = value;
        RaisePropertyChanged("Source");
    }
}

private double _volume;
public double Volume
{
    get { return _volume; }
    set
    {
        _volume = value;
        RaisePropertyChanged("Volume");
    }
}

public Action Play { get; set; }
public Action Stop { get; set; }
public Func<bool> Focus { get; set; }
public MediaElementBehavior()
{
}

protected override void OnAttached()
{
    base.OnAttached();

    MediaElement player = (MediaElement)this.AssociatedObject;
    MediaElementViewModel viewModel = (MediaElementViewModel)this.AssociatedObject.DataContext;

    player.Dispatcher.Invoke(() =>
    {
        // backing up the player methods inside its view-model.
        if (viewModel.Play == null)
            viewModel.Play = player.Play;

        if (viewModel.Stop == null)
            viewModel.Stop = player.Stop;

        if (viewModel.Focus == null)
            viewModel.Focus = player.Focus;
    });
}

protected override void OnDetaching()
{
    base.OnDetaching();
}
public MainViewModel()
{
    CurrentMediaElement = new MediaElementViewModel();
}

private MediaElementViewModel _currentMediaElement;
public MediaElementViewModel CurrentMediaElement
{
    get { return _currentMediaElement; }
    set
    {
        _currentMediaElement = value;
        RaisePropertyChanged("CurrentMediaElement");
    }
}

private RelayCommand _setSourceCommand;
public ICommand SetSourceCommand
{
    get
    {
        return _setSourceCommand ??
                (_setSourceCommand = new RelayCommand(SetSourceExecute));
    }
}
private RelayCommand _playCommand;
public ICommand PlayCommand
{
    get
    {
        return _playCommand ??
                (_playCommand = new RelayCommand(PlayExecute));
    }
}
private RelayCommand _stopCommand;
public ICommand StopCommand
{
    get
    {
        return _stopCommand ??
                (_stopCommand = new RelayCommand(StopExecute));
    }
}
private RelayCommand _focusCommand;
public ICommand FocusCommand
{
    get
    {
        return _focusCommand ??
            (_focusCommand = new RelayCommand(FocusExecute));
    }
}

/// <summary>
/// Invoked whenever focusing media element;
/// </summary>
private void FocusExecute()
{
    bool isFocused = this.CurrentMediaElement.Focus();
}

/// <summary>
/// Invoked whenever setting a media source.
/// </summary>
private void SetSourceExecute()
{
    // Assume the media file location is Debug/bin/Resources/
    this.CurrentMediaElement.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\media.mp3");
}
/// <summary>
/// Invoked whenever playing media.
/// </summary>
private void PlayExecute()
{
    this.CurrentMediaElement.Play();
}
/// <summary>
/// Invoked whenerver stopping media.
/// </summary>
private void StopExecute()
{
    this.CurrentMediaElement.Stop();
}
public主视图模型()
{
CurrentMediaElement=新MediaElementViewModel();
}
私有MediaElement视图模型_currentMediaElement;
公共MediaElement视图模型CurrentMediaElement
{
获取{return\u currentMediaElement;}
设置
{
_currentMediaElement=值;
RaisePropertyChanged(“CurrentMediaElement”);
}
}
私人中继通信(u setSourceCommand);;
公共ICommand设置资源命令
{
得到
{
返回设置资源命令??
(_setSourceCommand=newrelaycommand(SetSourceExecute));
}
}
专用中继命令(playCommand);;
公共ICommand播放命令
{
得到
{
返回\u playCommand??
(_playCommand=newrelaycommand(playcexecute));
}
}
专用中继命令_stopCommand;
公共ICommand stop命令
{
得到
{
返回_stop命令??
(_stopCommand=new RelayCommand(StopExecute));
}
}
私人关系社区(focusCommand);;
公共ICommand FocusCommand
{
得到
{
返回焦点命令??
(_focusCommand=newrelaycommand(FocusExecute));
}
}
/// 
///在聚焦媒体元素时调用;
/// 
私有void FocusExecute()
{
bool isFocused=this.CurrentMediaElement.Focus();
}
/// 
///在设置媒体源时调用。
/// 
私有void SetSourceExecute()
{
//假设媒体文件位置为Debug/bin/Resources/
this.CurrentMediaElement.Source=新Uri(AppDomain.CurrentDomain.BaseDirectory+“Resources\\media.mp3”);
}
/// 
///在播放媒体时调用。
/// 
私有void PlayExecute()
{
这个.CurrentMediaElement.Play();
}
/// 
///在停止媒体时调用。
/// 
私有void StopExecute()
{
这个.CurrentMediaElement.Stop();
}

如您所见(在MainViewModel.cs),我使用ViewModel-First方法从ViewModel调用了“纯”视图方法。(
PlayExecute
StopExecute
FocusExecute
)。

我找到了一个有效的解决方案,在找到更好的解决方案之前,我会保留它的答案

解决方案基于定制

需要注意的是,问题和答案在全局范围内,而不是
MediaElement
范围内。因此,此解决方案与支持ViewModel First方法的每个
框架元素
派生控件完全相关

为了清晰起见,我没有删除任何代码。

ViewTemplates.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication2"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <DataTemplate DataType="{x:Type local:MediaElementViewModel}">
        <MediaElement Source="{Binding Source}" Volume="{Binding Volume}"
                        LoadedBehavior="Manual" UnloadedBehavior="Manual">
            <i:Interaction.Behaviors>
                <local:MediaElementBehavior/>
            </i:Interaction.Behaviors>
        </MediaElement>
    </DataTemplate>
</ResourceDictionary>
<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ViewTemplates.xaml"/>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding CurrentMediaElement}"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Set Source" Command="{Binding SetSourceCommand}"/>
        <WrapPanel Grid.Row="1" Grid.Column="2">
            <Button Grid.Row="1" Grid.Column="2" Content="Stop" Command="{Binding StopCommand}"/>
            <Button Content="Focus" Command="{Binding FocusCommand}"/>
        </WrapPanel>

        <Button Grid.Row="1" Grid.Column="1" Content="Play" Command="{Binding PlayCommand}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding CurrentMediaElement.Source}" TextWrapping="Wrap"/>
        <Label Grid.Row="2" Grid.Column="1" Content="{Binding ElementName=SliderVolume, Path=Value}"/>
        <Slider x:Name="SliderVolume" Value="{Binding CurrentMediaElement.Volume}" Grid.Row="2" Grid.Column="2" Minimum="0" Maximum="1" Orientation="Horizontal"/>
    </Grid>
</Window>
以下是上述解决方案使用的示例:

App.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication2"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <DataTemplate DataType="{x:Type local:MediaElementViewModel}">
        <MediaElement Source="{Binding Source}" Volume="{Binding Volume}"
                        LoadedBehavior="Manual" UnloadedBehavior="Manual">
            <i:Interaction.Behaviors>
                <local:MediaElementBehavior/>
            </i:Interaction.Behaviors>
        </MediaElement>
    </DataTemplate>
</ResourceDictionary>
<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ViewTemplates.xaml"/>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding CurrentMediaElement}"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Set Source" Command="{Binding SetSourceCommand}"/>
        <WrapPanel Grid.Row="1" Grid.Column="2">
            <Button Grid.Row="1" Grid.Column="2" Content="Stop" Command="{Binding StopCommand}"/>
            <Button Content="Focus" Command="{Binding FocusCommand}"/>
        </WrapPanel>

        <Button Grid.Row="1" Grid.Column="1" Content="Play" Command="{Binding PlayCommand}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding CurrentMediaElement.Source}" TextWrapping="Wrap"/>
        <Label Grid.Row="2" Grid.Column="1" Content="{Binding ElementName=SliderVolume, Path=Value}"/>
        <Slider x:Name="SliderVolume" Value="{Binding CurrentMediaElement.Volume}" Grid.Row="2" Grid.Column="2" Minimum="0" Maximum="1" Orientation="Horizontal"/>
    </Grid>
</Window>

main window.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:WpfApplication2"
                    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <DataTemplate DataType="{x:Type local:MediaElementViewModel}">
        <MediaElement Source="{Binding Source}" Volume="{Binding Volume}"
                        LoadedBehavior="Manual" UnloadedBehavior="Manual">
            <i:Interaction.Behaviors>
                <local:MediaElementBehavior/>
            </i:Interaction.Behaviors>
        </MediaElement>
    </DataTemplate>
</ResourceDictionary>
<Application x:Class="WpfApplication2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ViewTemplates.xaml"/>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication2"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ContentControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding CurrentMediaElement}"/>
        <Button Grid.Row="1" Grid.Column="0" Content="Set Source" Command="{Binding SetSourceCommand}"/>
        <WrapPanel Grid.Row="1" Grid.Column="2">
            <Button Grid.Row="1" Grid.Column="2" Content="Stop" Command="{Binding StopCommand}"/>
            <Button Content="Focus" Command="{Binding FocusCommand}"/>
        </WrapPanel>

        <Button Grid.Row="1" Grid.Column="1" Content="Play" Command="{Binding PlayCommand}"/>
        <TextBlock Grid.Row="2" Grid.Column="0" Text="{Binding CurrentMediaElement.Source}" TextWrapping="Wrap"/>
        <Label Grid.Row="2" Grid.Column="1" Content="{Binding ElementName=SliderVolume, Path=Value}"/>
        <Slider x:Name="SliderVolume" Value="{Binding CurrentMediaElement.Volume}" Grid.Row="2" Grid.Column="2" Minimum="0" Maximum="1" Orientation="Horizontal"/>
    </Grid>
</Window>

MainViewModel.cs

public MediaElementViewModel()
{
    Volume = 0.5;
}

private Uri _source;
public Uri Source
{
    get { return _source; }
    set
    {
        _source = value;
        RaisePropertyChanged("Source");
    }
}

private double _volume;
public double Volume
{
    get { return _volume; }
    set
    {
        _volume = value;
        RaisePropertyChanged("Volume");
    }
}

public Action Play { get; set; }
public Action Stop { get; set; }
public Func<bool> Focus { get; set; }
public MediaElementBehavior()
{
}

protected override void OnAttached()
{
    base.OnAttached();

    MediaElement player = (MediaElement)this.AssociatedObject;
    MediaElementViewModel viewModel = (MediaElementViewModel)this.AssociatedObject.DataContext;

    player.Dispatcher.Invoke(() =>
    {
        // backing up the player methods inside its view-model.
        if (viewModel.Play == null)
            viewModel.Play = player.Play;

        if (viewModel.Stop == null)
            viewModel.Stop = player.Stop;

        if (viewModel.Focus == null)
            viewModel.Focus = player.Focus;
    });
}

protected override void OnDetaching()
{
    base.OnDetaching();
}
public MainViewModel()
{
    CurrentMediaElement = new MediaElementViewModel();
}

private MediaElementViewModel _currentMediaElement;
public MediaElementViewModel CurrentMediaElement
{
    get { return _currentMediaElement; }
    set
    {
        _currentMediaElement = value;
        RaisePropertyChanged("CurrentMediaElement");
    }
}

private RelayCommand _setSourceCommand;
public ICommand SetSourceCommand
{
    get
    {
        return _setSourceCommand ??
                (_setSourceCommand = new RelayCommand(SetSourceExecute));
    }
}
private RelayCommand _playCommand;
public ICommand PlayCommand
{
    get
    {
        return _playCommand ??
                (_playCommand = new RelayCommand(PlayExecute));
    }
}
private RelayCommand _stopCommand;
public ICommand StopCommand
{
    get
    {
        return _stopCommand ??
                (_stopCommand = new RelayCommand(StopExecute));
    }
}
private RelayCommand _focusCommand;
public ICommand FocusCommand
{
    get
    {
        return _focusCommand ??
            (_focusCommand = new RelayCommand(FocusExecute));
    }
}

/// <summary>
/// Invoked whenever focusing media element;
/// </summary>
private void FocusExecute()
{
    bool isFocused = this.CurrentMediaElement.Focus();
}

/// <summary>
/// Invoked whenever setting a media source.
/// </summary>
private void SetSourceExecute()
{
    // Assume the media file location is Debug/bin/Resources/
    this.CurrentMediaElement.Source = new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\media.mp3");
}
/// <summary>
/// Invoked whenever playing media.
/// </summary>
private void PlayExecute()
{
    this.CurrentMediaElement.Play();
}
/// <summary>
/// Invoked whenerver stopping media.
/// </summary>
private void StopExecute()
{
    this.CurrentMediaElement.Stop();
}
public主视图模型()
{
CurrentMediaElement=新MediaElementViewModel();
}
私有MediaElement视图模型_currentMediaElement;
公共MediaElement视图模型CurrentMediaElement
{
获取{return\u currentMediaElement;}
设置
{
_currentMediaElement=值;
RaisePropertyChanged(“CurrentMediaElement”);