【问题标题】:Changing the View for a ViewModel更改 ViewModel 的视图
【发布时间】:2011-03-15 08:23:03
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    更少的文字更多的代码。 正如你所说,你有课程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 库中的命令。

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

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

    【讨论】:

      【解决方案2】:

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

      • 您可以编写一个自定义数据求建器并在ContentControl.contentTemplateSelector上使用它,并选择两个模板
      • 如果这种更改视图的模式发生在许多不同的地方并且用户体验更频繁,我还建议使用基于 SampleViewModel 中的属性的 DataTemplate.DataTrigger 切换这两个视图 [我猜您可能在ViewModel 了解该状态]

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-06-21
          • 2011-03-04
          • 2012-05-28
          • 1970-01-01
          • 1970-01-01
          • 2013-02-28
          • 1970-01-01
          相关资源
          最近更新 更多