从祖先页面在 UserControl.Resources 中设置 ViewModel

Set ViewModel in UserControl.Resources from ancestor Page

假设我有如下用户控件。

<UserControl 
x:Class="MyApp.Controls.MyList"
xmlns:local="using:MyApp.Controls"
xmlns:viewModels="using:MyApp.ViewModels"
>
  <UserControl.Resources>
      <viewModels:CustomerViewModel x:Key="ViewModel"/>
  </UserControl.Resources>

  <UserControl.DataContext>
      <Binding Source="{StaticResource ResourceKey=ViewModel}" />
  </UserControl.DataContext>

  <UserControl.Content>
      <ListView ItemsSource={Binding ItemList} />
  </UserControl.Content>
</UserControl>

我在页面中使用此控件:

<Page
  x:Class="MyApp.Views.CustomerPage"
  xmlns:control="using:MyApp.Controls">

    <controls:MyList />

</Page>

到目前为止一切顺利。

现在我想为其他 ViewModel 重新使用相同的控件。我的 CustomerViewModel,就像我所有的视图模型一样,都是从接口 IViewModel 继承的。

如何使用相同的控件,比方说 SalesOrderViewModel?

我尝试了以下方法,但在 InitializeComponent() 时引发了 XamlParseException 异常:

<Page
  x:Class="MyApp.Views.CustomerPage"
  xmlns:control="using:MyApp.Controls">

    <controls:MyList>
      <controls:MyList.Resources>
        <viewModels:SalesOrderViewModel x:Key="ViewModel"/>
      </controls:MyList.Resources>
    </controls:>

</Page>

这里的工作方法是什么?

您可以为此使用数据模板。您可以使用视图模型设置数据模板的数据类型。

<UserControl.Resources>
  <DataTemplate DataType="{x:Type vm:ImageViewModel}" >
    <view:ImageView/>
  </DataTemplate>

  <DataTemplate DataType="{x:Type vm:VideoViewModel}">
    <view:VideoView/>
  </DataTemplate>
</UserControl.Resources>
<UserControl x:Class="Overlay.View.ImageView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Example.View"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
       <Image Source="/Assets/screenshot.png"/>   
    </Grid>
</UserControl>

<UserControl x:Class="Overlay.View.VideoView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:Example.View"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <MediaElement x:Name="Player" Source="./Assets/Sample_mp4.mp4"/>
</Grid>

假设您有一个用于页面控件的视图模型。这个视图模型可以有一个 属性 类型的 IViewModel ,它可以根据某些条件进行设置。您可以将此 属性 绑定到内容控件或内容呈现器的内容 属性。

<ContentControl Grid.Row="0" x:Name="ctnCtrl" Content="{Binding CurrentVm}"/>

内容控件将根据您选择的视图模型加载视图。

Viewmodel(只是我的速成,与你的有点不同):

public class ViewModel
{
    public string Value { get; set; } = "Default";
}

用户控件:

<UserControl
    x:Class="App1.MyList"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>
        <TextBlock Text="{Binding Value}" />
    </Grid>
</UserControl>

在页面中,为不同的Usercontrol设置不同的DataContext

<Page.Resources>
    <local:ViewModel x:Key="ViewModel1" Value="First"/>
    <local:ViewModel x:Key="ViewModel2" Value="Second"/>
</Page.Resources>

<StackPanel>
    <local:MyList DataContext="{StaticResource ViewModel1}" />
    <local:MyList DataContext="{StaticResource ViewModel2}" />
</StackPanel>