【问题标题】:WPF: TabControl with multiple DataTemplatesWPF:具有多个数据模板的 TabControl
【发布时间】:2017-06-16 20:48:13
【问题描述】:

我有一个TabControl 和多个DataTemplate。第一个DataTemplate 将用于搜索原因,第二个将用于显示从该搜索中获得的项目。我的XAML 代码如下:

 <UserControl.Resources>
    <!--First template-->
    <DataTemplate>
        <!-- I will have a DataGrid here-->
    </DataTemplate>

    <!--Second template-->
    <DataTemplate >
         <!-- I will have details of one item of the DataGrid-->
    </DataTemplate>
</UserControl.Resources>


<TabControl ItemsSource="{Binding }"/>

我想要完成的是,在TabControl 中,第一个选项卡将包含第一个 DataTemplate(搜索模板),当我双击 DataGrid 的一行时,将添加一个选项卡该行的详细信息(换句话说,带有第二个模板的选项卡)。

由于我使用的是MVVM,所以我想创建两个UserControls,每个模板一个,然后捕获双击事件,但是在此之后我不知道如何添加标签,因为现在我的搜索模板是一个UserControl,与包含TabControl 的模板分开。

那么我该怎么做呢?

更新:

当我阅读答案时,我认为我在陈述问题时并不是很清楚。 我的问题是如何通过从第一个模板捕获双击事件来使用第二个模板添加选项卡。我独立添加两个模板没有任何问题。

【问题讨论】:

    标签: c# wpf mvvm datatemplate tabcontrol


    【解决方案1】:

    可以创建两个UserControls,你可以创建并使用一个DataTemplateSelector来切换不同的DataTemplates。

    基本上,创建一个继承自DataTemplateSelector 的新类并覆盖SelecteTemplate 方法。然后在 XAML 中声明它的一个实例(很像一个值转换器),然后将它应用到 TabControlContentTemplateSelector 属性。

    More info can be found here.

    【讨论】:

      【解决方案2】:

      如果您要使用 MVVM 执行此操作,您的选项卡控件应绑定到 VM 中的某个 ObservableCollection,您只需根据需要将 VM 添加和删除到集合中。

      VM 可以是您喜欢的任何类型,并且您的 DataTemplates 将在选项卡中显示正确的视图,就像任何其他视图一样,所以是的,为这两个视图创建两个 UserControl。

      public class MainVM
      {
          public ObservableCollection<object> Views { get; private set; }
      
          public MainVM()
          {
              this.Views = new ObservableCollection<object>();
              this.Views.Add(new SearchVM(GotResults));
          }
      
          private void GotResults(Results results)
          {
              this.Views.Add(new ResultVM(results));
          }
      }
      

      【讨论】:

      • 您正在从 viewmodel 访问 UI 元素(视图),这通常被认为是不好的做法,因为它违反了“关注点分离”mvvm 原则。理想情况下,您应该只访问视图模型层中的其他视图模型、模型或服务。在这种情况下,很容易保持这个原则,并且有显着的好处。
      • 不。我知道该集合称为 Views,但它包含 VM。它是一个概念视图,而不是实际的 UI 视图。可以将其称为 Tabs 或其他名称。这是一个标准的 MVVM 模式
      • 那样的话,我没有异议:)
      【解决方案3】:

      有两种选择:使用数据模板选择器,或为每个标签项使用隐式数据模板和不同类型。

      1.数据模板选择器:

      public ObservableCollection<TabItemVM> Tabs { get; private set; }
      
      public MainVM()
      {
          Tabs = ObservableCollection<TabItemVM>
          {
              new TabItemVM { Name="Tab 1" },
          };
      }
      
      void AddTab(){
         var newTab = new TabItemVM { Name="Tab 2" };
         Tabs.Add(newTab);
         //SelectedTab = newTab; //you may bind TabControl.SelectedItemProperty to viewmodel in order to be able to activate the tab from viewmodel
      }
      
      public class TabItemTemplateSelector : DataTemplateSelector
      {
          public DataTemplate Tab1Template { get; set; }
          public DataTemplate Tab2Template { get; set; }
          public override DataTemplate SelectTemplate(object item, DependencyObject container)
          {
              var tabItem = item as TabItemVM;
              if (tabItem.Name == "Tab 1") return Tab1Template;
              if (tabItem.Name == "Tab 2") return Tab2Template;
              return base.SelectTemplate(item, container);
          }
      }
      
      <local:TabItemTemplateSelector
           x:Key="TabItemTemplateSelector"
           Tab1Template="{StaticResource Tab1Template}" 
           Tab2Template="{StaticResource Tab2Template}" />
      

      2。隐式数据模板:

      public class MainVM : ViewModelBase
      {
          public ObservableCollection<TabItemVM> Tabs { get; private set; }
      
          public MainVM()
          {
              Tabs = new ObservableCollection<TabItemVM>
              {
                  new Tab1VM(),
              };
          }
      
          void AddTab()
          {
              var newTab = new Tab2VM()
              Tabs.Add(newTab);
             //SelectedTab = newTab; 
          }
      }
      
      public class TabItemBase
      {
          public string Name { get; protected set; }
      }
      
      public class Tab1VM : TabItemBase
      {
          public Tab1VM()
          {
              Name = "Tab 1";
          }
      }
      
      public class Tab2VM : TabItemBase
      {
          public Tab2VM()
          {
              Name = "Tab 2";
          }
      }
      
      <UserControl.Resources>
         <!--First template-->
         <DataTemplate DataType="local:Tab1VM">
             <!-- I will have a DataGrid here-->
         </DataTemplate>
      
         <!--Second template-->
         <DataTemplate DataType="local:Tab2VM">
             <!-- I will have details of one item of the DataGrid-->
         </DataTemplate>
      </UserControl.Resources>
      

      【讨论】:

      • 这两种方法我都知道,但这不是我的问题,可能我不是很清楚。我遇到的问题是第二个模板将从第一个模板捕获的事件中添加。如果要同时添加两个模板是一件容易的事。
      • 在这种情况下,将 Tabs 属性的类型更改为 ObservableCollection 。两种方法都应该起作用。您还可以将TabControl.SelectedItem 属性绑定到MainVM.SelectedTab 属性,这样您就可以从视图模型中激活新创建的选项卡
      猜你喜欢
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多