单个ViewModel的多个视图

时间:2016-02-26 09:26:55

标签: c# wpf xaml mvvm datatemplate

问题

我的WPF Window中有多个按钮,点击后需要更改Window上的视图,但保持相同ViewModel。昨天我尝试使用ControlTemplate,但人们提到我最好使用DataTemplate.

我需要通过ViewModel进行绑定以及我需要进行一些检查以查看用户是否可以访问视图。

代码

这是我开始编写的一些代码,但我觉得它不正确。

以下是DataTemplate中我在视图中定义的Window.Resources

    <DataTemplate x:Key="panel1">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="7*"/>
                <ColumnDefinition Width="110*"/>
                <ColumnDefinition Width="190*"/>
                <ColumnDefinition Width="110*"/>
                <ColumnDefinition Width="202*"/>
                <ColumnDefinition Width="109*"/>
                <ColumnDefinition Width="7*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="74*"/>
                <RowDefinition Height="50*"/>
                <RowDefinition Height="12*"/>
                <RowDefinition Height="39*"/>
                <RowDefinition Height="11*"/>
                <RowDefinition Height="38*"/>
                <RowDefinition Height="5*"/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Column="2" Grid.ColumnSpan="3" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Label Content="Video Set:" Foreground="#e37e6e" Grid.Column="2" Grid.ColumnSpan="3" VerticalAlignment="Center" FontSize="22" HorizontalAlignment="Center"/>
                <Image Source="{Binding VideoSet}" Height="25" Width="25" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </StackPanel>

            <TextBlock Foreground="#e37e6e" FontSize="12" Text="You currently do not have a video set. Please click the button below to add a video. Please note you will not be able to create an On Demand presentation without a media file selected. " Grid.Row="1" Grid.Column="2" TextWrapping="WrapWithOverflow" TextAlignment="Center" Grid.ColumnSpan="3" />
            <Button Style="{StaticResource loginButton}" Command="{Binding ScreenBack}" Foreground="White" Content="Add Video" Grid.Column="3" HorizontalAlignment="Stretch" Grid.Row="3" VerticalAlignment="Stretch" Grid.ColumnSpan="1"></Button>

        </Grid>
    </DataTemplate>

然后我尝试使用ContentPresenter并绑定到DataTemplate

<ContentPresenter Content="{Binding}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>

现在我希望能够通过DataTemplatesContentPresenter绑定到ViewModel,有人可以帮我解决这个问题吗?

编辑:

我可以通过以下静态资源将ContentPresenter绑定到DataTemplate

<ContentPresenter ContentTemplate="{StaticResource panel1}" Content="{StaticResource panel1}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>

DataTemplate如下所示:

<DataTemplate x:Key="panel1">

</DataTemplate>

但是如何更改ControlPresenter的{​​{1}}绑定?

编辑:

这是我的代码周期:

所以这是两个DataTemplates:

ViewModel

我的ContentControl:

<DataTemplate DataType="{x:Type local:ViewModelA}">
     <TextBlock Foreground="#e37e6e" FontSize="12" Text="You currently do not have a video set. Please click the button below to add a video. Please note you will not be able to create an On Demand presentation without a media file selected. " Grid.Row="1" Grid.Column="2" TextWrapping="WrapWithOverflow" TextAlignment="Center" Grid.ColumnSpan="3" />
</DataTemplate>

<DataTemplate DataType="{x:Type local:ViewModelB}">
     <TextBlock Foreground="#e37e6e" FontSize="12" Text="NEWWWWWWWWWWYou" Grid.Row="1" Grid.Column="2" TextWrapping="WrapWithOverflow" TextAlignment="Center" Grid.ColumnSpan="3" />
</DataTemplate>

我在后面的代码中定义了我的DataContext:

<ContentControl Content="{Binding SelectedViewModel}" />

在WizardViewModel中我有:

WizardViewModel _wizardViewModel = new WizardViewModel();
this.DataContext = _wizardViewModel;

2 个答案:

答案 0 :(得分:3)

数据模板使用起来要简单得多(与您的尝试相比):

  • 创建子视图模型,每个子视图对应一个

// could have base class, may have to implement INotifyPropertyChanged, etc.
public class ViewModelA { }
public class ViewModelB
{
    public string SomeProperty { get; }
}
...

public object SelectedViewModel { get; set; }
  • 定义数据模板

<SomeContainer.Resources>
    <!-- using user control -->
    <DataTemplate DataType="{x:Type local:ViewModelA}">
        <local:UserControlA />
    </DataTemplate>
    <!-- or like this -->
    <DataTemplate DataType="{x:Type local:ViewModelB}">
        <Grid>
            <TextBlock Text="{Binding SomeProperty}" />
            <Button .../>
            ...
        </Grid>
    </DataTemplate>
  • 将内容控件绑定到选择子视图模型的属性

<ContentControl Content="{Binding SelectedViewModel}" />
  • 通过更改选定的子视图模型来控制要显示的内容:

var a = new ViewModelA();
var b = new ViewModelB() { SomeProperty = "Test" };

// display a - will display UserControlA content in ContentControl
SelectedViewModel = a;
OnPropertyChanged(nameof(SelectedViewModel));

// display b - will display text and button in ContentControl
SelectedViewModel = b;
OnPropertyChanged(nameof(SelectedViewModel));

答案 1 :(得分:1)

DataTemplate存储为ViewModel的属性。从ResourceDictionary访问DataTemplate以存储在您的媒体资源中。

绑定<ContentPresenter Content="{Binding}" ContentTemplate="{Binding template1}" .../>

如何从代码中访问ResourceDictionary:

如果您的WPF项目中有一个用于定义资源的ResourceDictionary,您可以使用以下代码创建它的实例:

ResourceDictionary res = Application.LoadComponent(
 new Uri("/WpfApplication1;component/MyDataTemplateCollection.xaml", 
 UriKind.RelativeOrAbsolute)) as ResourceDictionary;

其中WpfApplication1是程序集的名称,MyDataTemplateCollection.xaml是ResourceDictionary的名称。

另一种方法是使用代码隐藏资源字典。

将x:Class添加到ResourceDictionary:

添加类MyDataTemplateCollection.xaml.cs作为ResourceDictionary的代码隐藏。

类背后的代码如下:

partial class MyDataTemplateCollection: ResourceDictionary
{
   public MyDataTemplateCollection()
   {
      InitializeComponent();
   }     
}

用法:

ResourceDictionary res = new MyDataTemplateCollection();