从嵌套的tabcontrols填充树视图

时间:2015-05-08 16:24:53

标签: c# wpf xaml treeview tabcontrol

我正在构建一个设置窗口,左侧有TreeView,右侧有TabControl - 布局基于Microsoft Visual Studio选项对话框。

TabControl有3 TabItems,因此有3个标签。每个TabItems都包含一个TabControl,其中包含2个TabItems。我计划稍后隐藏TabControl标签,但回到TreeView,它将如下所示:

  • 选项组1
    • 子选项组1
    • 子选项组2
  • 选项组2
    • 子选项组1
    • 子选项组2
  • 选项组3
    • 子选项组1
    • 子选项组2

在我的XAML中,一切都在视觉上正常。我正试图弄清楚这个代码隐藏。

我想拥有它,因此点击TreeView中的项目会导致相应的TabItem生效。如何获取Treeview所选项目/节点并导致所有TabControls做出反应?

我在质疑这是否是最佳方式。我必须维护TreeView项和TabControl TabItems ...

1 个答案:

答案 0 :(得分:0)

制表符(树)项

的表示形式

让我们定义一些用作嵌套控件模型的类。它基本上是一棵树,孩子们将IsSelected财产的变化传播给他们的父母:

public class TabItemModel : INotifyPropertyChanged
{
    private TabItemModel m_parent;
    private Boolean m_IsSelected;

    public TabItemModel(String name) : this(name, null)
    {
    }

    public TabItemModel(String name, IEnumerable<TabItemModel> children)
    {
        this.Name = name;

        this.Children = new ObservableCollection<TabItemModel>(children ?? Enumerable.Empty<TabItemModel>());

        foreach (var child in this.Children)
        {
            child.m_parent = this;
        }
    }

    public String Name
    {
        get;
        set;
    }

    public ObservableCollection<TabItemModel> Children
    {
        get;
        private set;
    }

    public Boolean IsSelected
    {
        get
        {
            return this.m_IsSelected;
        }
        set
        {
            if (value == this.m_IsSelected)
                return;

            if (this.m_parent != null)
                this.m_parent.IsSelected = value;

            this.m_IsSelected = value;

            this.OnPropertyChanged();
        }
    }

    protected void OnPropertyChanged([CallerMemberName]String propertyName = null)
    {
        var propChangedDelegate = this.PropertyChanged;

        if (propChangedDelegate == null)
            return;

        propChangedDelegate(this,
            new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

主ViewModel

我们需要一些主视图模型:

  1. 包含此类TabItemModels
  2. 提供选定的tabitemmodel属性以与treeview中的selectedItem进行互操作
  3. 代码:

    public class TabsViewModel
    {
        public TabsViewModel()
        {
            this.Items = GetItems();
        }
    
        private TabItemModel _SelectedItem;
    
        public TabItemModel SelectedItem
        {
            get
            {
                return this._SelectedItem;
            }
            set
            {
                if (value == this._SelectedItem)
                    return;
    
                if (value != null)
                {
                    if (this._SelectedItem != null)
                        this._SelectedItem.IsSelected = false;
    
                    value.IsSelected = true;
                }
    
                this._SelectedItem = value;
            }
        }
    
        public ObservableCollection<TabItemModel> Items
        {
            get;
            private set;
        }
    
        private ObservableCollection<TabItemModel> GetItems()
        {
            return new ObservableCollection<TabItemModel>()
            {
                new TabItemModel("Tab 1", 
                    new TabItemModel[] 
                    {
                        new TabItemModel("Tab 1 - SubTab 1"),
                        new TabItemModel("Tab 1 - SubTab 2")
                    }),
                new TabItemModel("Tab 2", 
                    new TabItemModel[] 
                    {
                        new TabItemModel("Tab 2 - SubTab 1"),
                        new TabItemModel("Tab 2 - SubTab 2")
                    }),
                new TabItemModel("Tab 3", 
                    new TabItemModel[] 
                    {
                        new TabItemModel("Tab 3 - SubTab 1"),
                        new TabItemModel("Tab 3 - SubTab 2")
                    })
            };
        }
    }
    

    代码隐藏

    public MainWindow()
    {
        InitializeComponent();
    
        this.DataContext = new TabsViewModel();
    }
    

    XAML

    这是最不美好的事情。我无法两者:

    1. 创建普通的分层嵌套TabControls。
    2. 将他们的IsSelected与绑定项目IsSelected连接在datatemplates中。
    3. 所以,现在我只能提出以下带有硬编码tabItem的XAML:

      <Grid>
          <Grid.ColumnDefinitions>
              <ColumnDefinition/>
              <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <TreeView Grid.Row="0" Grid.Column="0" 
                    ItemsSource="{Binding Items}">
              <blend:Interaction.Behaviors>
                  <view:BindableSelectedItemBehavior SelectedItem="{Binding SelectedItem, Mode=TwoWay}" />
              </blend:Interaction.Behaviors>
              <TreeView.Resources>
                  <DataTemplate x:Key="tabItemTemplateLeaf">
                      <StackPanel Orientation="Horizontal">
                          <TextBlock Text="{Binding Name}"/>
                      </StackPanel>
                  </DataTemplate>
                  <HierarchicalDataTemplate x:Key="tabItemTemplate" 
                                            ItemTemplate="{StaticResource tabItemTemplateLeaf}" ItemsSource="{Binding Children}">
                      <StackPanel Orientation="Horizontal">
                          <TextBlock Text="{Binding Name}"/>
                      </StackPanel>
                  </HierarchicalDataTemplate>
              </TreeView.Resources>
              <TreeView.ItemTemplate>
                  <StaticResource ResourceKey="tabItemTemplate"/>
              </TreeView.ItemTemplate>            
          </TreeView>
          <TabControl Grid.Row="0" Grid.Column="1">
              <TabItem DataContext="{Binding Items[0]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}">
                  <TabControl>
                      <TabItem  DataContext="{Binding Children[0]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}"/>
                      <TabItem  DataContext="{Binding Children[1]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}"/>
                  </TabControl>
              </TabItem>
              <TabItem DataContext="{Binding Items[1]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}">
                  <TabControl>
                      <TabItem  DataContext="{Binding Children[0]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}"/>
                      <TabItem  DataContext="{Binding Children[1]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}"/>
                  </TabControl>
              </TabItem>
              <TabItem DataContext="{Binding Items[2]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}">
                  <TabControl>
                      <TabItem  DataContext="{Binding Children[0]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}"/>
                      <TabItem  DataContext="{Binding Children[1]}" Header="{Binding Name}" IsSelected="{Binding IsSelected}"/>
                  </TabControl>
              </TabItem>
          </TabControl>
      </Grid>
      

      它使用来自this SO answer的混合行为类来允许绑定到TreeView的SelectedItem属性(您需要将System.Windows.Interactions.dll添加到项目中并xmlns:blend="http://schemas.microsoft.com/expression/2010/interactivity"添加到您的XAML中

      P.S:我将尝试解决XAML部分中描述的问题,但是现在它是我能提出的最好的问题。