更改ViewModel的视图

时间:2011-03-15 08:23:03

标签: c# wpf mvvm

我正在尝试为mt WPF应用程序实现MVVM设计模式。为了将视图连接到视图模型,我使用ResourceDictionary(在Application.Resources中使用),看起来像

<DataTemplate DataType={x:Type viewmodel:SampleViewModel}>
    <view:SampleView1 />
</DataTemplate>

然后将视图模型简单地放入内容演示者中以显示它们。

现在,当用户按下按钮时,我想使用不同的视图显示SampleViewModel。如何更改用于SampleViewModel的数据模板?

3 个答案:

答案 0 :(得分:9)

少说更多代码。 据你所说,你有班级SampleViewModel。我添加了属性Title用于演示,ViewType用于标识正确的视图:

public enum ItemViewType { View1, View2 };

public class SampleViewModel 
{
    public string Title { get; set; }
    public ItemViewType ViewType { get; set; }
}

两个视图的DataTemplateSelector取决于ViewType属性:

class ItemViewTemplateSelector : DataTemplateSelector
{
    public DataTemplate View1Template { get; set; }
    public DataTemplate View2Template { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var vm = item as SampleViewModel;
        if (vm == null)
            return null;

        switch (vm.ViewType)
        {
            case ItemViewType.View1:
                return View1Template;
            case ItemViewType.View2:
                return View2Template;
        }

        return null;
    }
}

Xaml代码:

<Window.Resources>
    <DataTemplate x:Key="view1Template">
        <TextBlock Text="{Binding Title}" Foreground="Red"/>
    </DataTemplate>
    <DataTemplate x:Key="view2Template">
        <TextBox Text="{Binding Title}" />
    </DataTemplate>
    <local:ItemViewTemplateSelector x:Key="viewTemplateSelector"
                                    View1Template="{StaticResource view1Template}"
                                    View2Template="{StaticResource view2Template}"/>
</Window.Resources>

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

<StackPanel>
    <Button Content="ChangeView" HorizontalAlignment="Center" Command="{Binding SwitchViewCommand}"/>
    <ContentControl  Content="{Binding ItemViewModel}" ContentTemplateSelector="{StaticResource viewTemplateSelector}"/>
</StackPanel>

主要部分在班级MainViewModel中,我已经把逻辑用于切换视图:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        this.ItemViewModel = new SampleViewModel { Title = "Some title", ViewType = ItemViewType.View1 };

        this.SwitchViewCommand = new RelayCommand(() =>
        {
            this.ItemViewModel.ViewType = this.ItemViewModel.ViewType == ItemViewType.View1
                                            ? ItemViewType.View2
                                            : ItemViewType.View1;
            //The magic senquence of actions which forces a contentcontrol to change the content template
            var copy = this.ItemViewModel;
            this.ItemViewModel = null;
            this.ItemViewModel = copy;
        });
    }

    public RelayCommand SwitchViewCommand { get; set; }

    private SampleViewModel itemViewModel;

    public SampleViewModel ItemViewModel
    {
        get { return itemViewModel; }
        set
        {
            itemViewModel = value;
            RaisePropertyChanged("ItemViewModel");
        }
    }
}

SwitchViewCommand可以是任何类型的命令,我使用mvvmlight库中的命令。

在命令的处理程序中,我更改了viewmodel的类型并以一种棘手的方式更新属性ItemViewModel,因为ContentControl仅在更改Content属性时刷新视图,并且此属性将除非您设置对不同对象的引用,否则不得更改。

我的意思是,即使代码this.ItemViewModel = this.itemViewModel也不会更改视图。 这很奇怪,但解决方法并不需要太多工作。

答案 1 :(得分:1)

您可以通过在树中放置较低的类似资源来覆盖映射。由于WPF将通过向上搜索来解析资源,因此这种覆盖将替换您现有的映射。

答案 2 :(得分:1)

您可以通过多种不同的方式实现这一目标,具体取决于您想要的架构。

  • 您可以编写自定义DataTemplateSelector并在ContentControl.ContentTemplateSelector上使用它并适当选择这两个模板
  • 如果这种更改视图的模式在许多不同的地方出现并且更频繁的用户体验,我还建议使用基于SampleViewModel中的属性的DataTemplate.DataTrigger切换这两个视图[我猜你可能有一个区别属性ViewModel知道那个状态]