zoukankan      html  css  js  c++  java
  • WPF-菜单和Tab控件

    WPF-菜单和Tab控件

      因为菜单和Tab控件一起用,所以就拿出来一块写

    Tab控件

      定义一个名为ViewItem类,定义Tab的属性

     1 /// <summary>
     2     /// tab  item
     3     /// </summary> 
     4     public class ViewItem
     5     {
     6         /// <summary>
     7         /// 标题
     8         /// </summary>
     9         public string Header
    10         {
    11             get;
    12             set;
    13         }
    14 
    15         /// <summary>
    16         /// 主键名称
    17         /// </summary>
    18         public string KeyName
    19         {
    20             get;
    21             set;
    22         }
    23 
    24         /// <summary>
    25         /// the show Control
    26         /// </summary>
    27         public object ViewControl
    28         {
    29             get;
    30             set;
    31         }
    32     }

      TabControl用的是Dev的控件,所以先要引用三个Dev的DLL,分别是DevExpress.Xpf.Core,DevExpress,Xpf.Docking,DevExpress.Xpf.Layout.Core。

      新建一个UserControl,命名为MenuControl,在主窗体的Window中需要添加一下引用

    1         xmlns:dxd="http://schemas.devexpress.com/winfx/2008/xaml/docking"2         xmlns:c="clr-namespace:RemindWin"
    3         xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
    4         Name="MainView_View"

      其中,c引用的是MenuControl所在的文件夹,因为要用到MenuControl,所以需要引用MenuControl所在的文件夹。并为窗体命名为“MainView_View”(后面用到)。

      定义一个DockPanel,在其的顶端设置菜单栏,内容放TabControl,也可以在下面放FootBar,这里省略,主窗体代码如下:

     1 <Grid x:Name="MainView">
     2         <DockPanel LastChildFill="True">
     4             <c:MenuControl DockPanel.Dock="Top" HorizontalAlignment="Left"/>
     5             <dxd:DockLayoutManager x:Name="dockManager" UseLayoutRounding="True" AllowCustomization="False">
     6                 <dxd:LayoutGroup Orientation="Vertical" >
     7                     <dxd:DocumentGroup Name="documentContainer" 
     8                                    SelectedTabIndex="{Binding SelectedTabIndex,Mode=TwoWay}"
     9                                    ItemsSource="{Binding ItemList}"
    10                                    DestroyOnClosingChildren="False" 
    11                                    Background="Azure"
    12                                    ClosePageButtonShowMode="InActiveTabPageAndTabControlHeader">
    13                         <dxd:DocumentGroup.ItemStyle>
    14                             <Style TargetType="dxd:DocumentPanel">
    15                                 <Setter Property="CloseCommand" Value="{Binding DataContext.CloseCommand,ElementName=MainView}" />
    16                                 <Setter Property="Caption" Value="{Binding Header}"></Setter>
    17                                 <Setter Property="AllowFloat" Value="False"></Setter>
    18                                 <Setter Property="AllowMaximize" Value="False"></Setter>
    19                             </Style>
    20                         </dxd:DocumentGroup.ItemStyle>
    21                         <dxd:DocumentGroup.ItemContentTemplate>
    22                             <DataTemplate>
    23                                 <ContentControl Content="{Binding ViewControl}"></ContentControl>
    24                             </DataTemplate>
    25                         </dxd:DocumentGroup.ItemContentTemplate>
    26                     </dxd:DocumentGroup>
    27                 </dxd:LayoutGroup>
    28             </dxd:DockLayoutManager>
    29         </DockPanel>
    30     </Grid>

      binding了Model中的ItemList,这是Tab集合,SelectedTabIndex是所选Tab的索引,为Int型,每个Tab有一个Close事件,Binding后台代码中的CloseCommand事件,属性Caption,banding了ViewItem中的Header,每个Tab的内容ContentControl绑定了ViewItem中的ViewControl,其中需要注意Grid的Name与<Setter>里面的元素一致。

      添加主窗体的ViewModel,命名MainViewModel,定义ItemList和SelectedTabIndex(引用了SimpleMvvmToolkit)

     1         #region Properties
     2 
     3         //
     4         private ObservableCollection<ViewItem> _itemList = new ObservableCollection<ViewItem>();
     5         /// <summary>
     6         /// Tab页集合
     7         /// </summary>
     8         public ObservableCollection<ViewItem> ItemList
     9         {
    10             get
    11             {
    12                 return _itemList;
    13             }
    14             set
    15             {
    16                 _itemList = value;
    17             }
    18         }
    19 
    20         //所选tab索引
    21         private int _selectedTabIndex = 0;
    22         /// <summary>
    23         /// 所选tab索引
    24         /// </summary>
    25         public int SelectedTabIndex
    26         {
    27             get
    28             {
    29                 return _selectedTabIndex;
    30             }
    31             set
    32             {
    33                 _selectedTabIndex = value;
    34                 NotifyPropertyChanged(x => x.SelectedTabIndex);
    35             }
    36         }
    37 
    38         #endregion
    View Code

      定义添加Tab的方法,定义了两个,一个ViewModel是为类型的方法,一个ViewModel以参数形式的方法,第二种主要是针对一些需要传参的ViewModel,这里有一个规则,如果一个需要添加一个已有的Tab页,会自动跳到该Tab页,而不是出现两个一样的Tab页,这里主要依靠KeyName做判断(也可添加两个一样的Tab,代码需简单修改)

     1         /// <summary>
     2         /// 添加Tab页
     3         /// </summary>
     4         /// <typeparam name="TView">View</typeparam>
     5         /// <typeparam name="KMode">ViewModel</typeparam>
     6         /// <param name="header">对应的标题</param>
     7         /// <param name="systemFunction">View的类型</param>
     8         public void OpenNewItem<TView, KMode>(string header, string systemFunction)
     9             where TView : System.Windows.Controls.UserControl, new()
    10             where KMode : new()
    11         {
    12             string keyName = systemFunction.ToString();
    13             var q = ItemList.Where(x => x.KeyName == keyName).FirstOrDefault();
    14             int index = 0;
    15             if (q == null)
    16             {
    17                 KMode vModel = new KMode();
    18                 TView view = new TView();
    19                 ViewItem item = new ViewItem();
    20                 item.Header = header;
    21                 item.KeyName = keyName;
    22                 item.ViewControl = view;
    23                 ItemList.Add(item);
    24                 view.DataContext = vModel;
    25                 index = ItemList.Count() - 1;
    26             }
    27             else
    28             {
    29                 index = ItemList.IndexOf(q);
    30             }
    31             SelectedTabIndex = index;
    32         }
    33 
    34         /// <summary>
    35         /// 添加Tab页
    36         /// </summary>
    37         /// <typeparam name="TView">View</typeparam>
    38         /// <param name="header">对应的标题</param>
    39         /// <param name="systemFunction">View的类型</param>
    40         /// <param name="_model">可带参数的ViewModel</param>
    41         public void OpenNewItemPara<TView>(string header, string systemFunction,object _model)
    42             where TView : System.Windows.Controls.UserControl, new()
    43         {
    44             string keyName = systemFunction.ToString();
    45             var q = ItemList.Where(x => x.KeyName == keyName).FirstOrDefault();
    46             int index = 0;
    47             if (q == null)
    48             {
    49                 TView view = new TView();
    50                 ViewItem item = new ViewItem();
    51                 item.Header = header;
    52                 item.KeyName = keyName;
    53                 item.ViewControl = view;
    54                 ItemList.Add(item);
    55                 view.DataContext = _model;
    56                 index = ItemList.Count() - 1;
    57             }
    58             else
    59             {
    60                 index = ItemList.IndexOf(q);
    61             }
    62             SelectedTabIndex = index;
    63         }

      定义关闭Tab的事件和方法

     1         /// <summary>
     2         /// 关闭Tab页
     3         /// </summary>
     4         public DelegateCommand CloseCommand
     5         {
     6             get
     7             {
     8                 return new DelegateCommand(CloseTab);
     9             }
    10         }
    11 
    12         private void CloseTab()
    13         {
    14             if (SelectedTabIndex >= 0)
    15             {
    16                 var q = ItemList[SelectedTabIndex];
    17                 ItemList.RemoveAt(SelectedTabIndex);
    18                 ((System.Windows.Controls.UserControl)q.ViewControl).DataContext = null;
    19                 q.ViewControl = null;
    20                 q = null;
    21                 GC.Collect();
    22                 GC.WaitForPendingFinalizers();
    23                 GC.Collect();
    24             }
    25         }
    View Code

      别忘了,在MainWindow.xaml.cs的构造中添加这句话

    1 this.DataContext = new MainViewModel();

    MenuControl菜单栏

      定义MenuItem

     1     /// <summary>
     2     /// 主菜单项。可添加更多属性实现菜单的个性配置,如字体、图片、响应等
     3     /// </summary>
     4     public class MenuItem : ModelBase<MenuItem>
     5     {
     6         public MenuItem(string item)
     7         {
     8             Header = item;
     9             Childrens = new List<MenuItem>();
    10         }
    11 
    12         public MenuItem(string header, string keyName)
    13         {
    14             Header = header;
    15             KeyName = keyName;
    16         }
    17 
    18         /// <summary>
    19         /// 菜单名称,做为菜单主键
    20         /// </summary>
    21         public string KeyName
    22         {
    23             get;
    24             set;
    25         }
    26 
    27         /// <summary>
    28         /// 菜单名
    29         /// </summary>
    30         public string Header { get; set; }
    31 
    32         /// <summary>
    33         /// 图片
    34         /// </summary>
    35         public BitmapImage Icon { get; set; }
    36 
    37         /// <summary>
    38         /// 是否可用
    39         /// </summary>
    40         private bool m_IsEnabled = true;
    41         /// <summary>
    42         /// 菜单可用性。判断权限后设置此属性实现菜单的可用性控制
    43         /// </summary>
    44         new public bool IsEnabled
    45         {
    46             get
    47             {
    48                 return m_IsEnabled;
    49             }
    50             set
    51             {
    52                 m_IsEnabled = value;
    53                 NotifyPropertyChanged(x => x.IsEnabled);
    54             }
    55         }
    56 
    57         /// <summary>
    58         /// 子菜单
    59         /// </summary>
    60         public List<MenuItem> Childrens { get; set; }
    61 
    62         /// <summary>
    63         /// 事件
    64         /// </summary>
    65         public DelegateCommand<string> SelectedCommand { get; set; }
    66 
    67        
    68     }
    View Code

      在MenuControl中定义各种格式和属性

     1     <UserControl.Resources>
     2         <HierarchicalDataTemplate x:Key="ItemTemplate"
     3                                   ItemsSource="{Binding Childrens}">
     4             <StackPanel Orientation="Horizontal"  VerticalAlignment="Center">
     5                 <TextBlock Text="{Binding Header}"
     6                        IsEnabled="{Binding IsEnabled}"  VerticalAlignment="Center"/>
     7             </StackPanel>
     8         </HierarchicalDataTemplate>
     9         <ControlTemplate x:Key="MenuSeparatorTemplate">
    10             <Separator />
    11         </ControlTemplate>
    12     </UserControl.Resources>
    13 
    14     <Menu DockPanel.Dock="Top"
    15           VerticalAlignment="Top"
    16           ItemsSource="{Binding MenuList}"
    17           ItemTemplate="{StaticResource ItemTemplate}">
    18 
    19         <!-- 菜单背景色-->
    20         <Menu.Background>
    21             <LinearGradientBrush StartPoint="0,0" EndPoint="0,1.5">
    22                 <GradientStop Color="#f2f2f2" Offset="0.5"/>
    23                 <GradientStop Color="#F8F9FB" Offset="01"/>
    24             </LinearGradientBrush>
    25         </Menu.Background>
    26         <Menu.ItemContainerStyle>
    27             <Style TargetType="MenuItem">
    28                 <Setter Property="IsEnabled"
    29                         Value="{Binding IsEnabled}" />
    30                 <Setter Property="Command"
    31                         Value="{Binding SelectedCommand}" />
    32                 <Setter Property="CommandParameter"
    33                         Value="{Binding Header}" />
    34                 <Setter Property="FontSize" Value="14"/>
    35                
    36                 <Style.Triggers>
    37                     <DataTrigger Binding="{Binding }"
    38                                  Value="{x:Null}">
    39                         <Setter Property="Template"
    40                                 Value="{StaticResource MenuSeparatorTemplate}" />
    41                     </DataTrigger>
    42                 </Style.Triggers>
    43 
    44             </Style>
    45         </Menu.ItemContainerStyle>
    46     </Menu>
    View Code

      定义菜单的ViewModel,名为MenuControlModel,定义属性

     1         #region Properties
     2 
     3         private List<MenuItem> m_MainMenus = new List<MenuItem>();
     4         public List<MenuItem> MenuList
     5         {
     6             get
     7             {
     8                 return m_MainMenus;
     9             }
    10             set
    11             {
    12                 m_MainMenus = value;
    13                 NotifyPropertyChanged(x => x.MenuList);
    14             }
    15         }
    16 
    17         #endregion

      定义递归设置所有菜单的命令

     1         /// <summary>
     2         /// 递归设置所有菜单的命令
     3         /// </summary>
     4         /// <param name="Menus"></param>
     5         void SetMenuCommand(List<MenuItem> Menus)
     6         {
     7             foreach (var item in Menus)
     8             {
     9                 item.SelectedCommand = new DelegateCommand<string>(OpenMenu);
    10                 if (item.Childrens.Count > 0) SetMenuCommand(item.Childrens);
    11             }
    12         }

      定义点击菜单Item时执行的方法,其中第一个判断是找到主窗体,再进行操作,如果菜单的Name中包含“测试”两个字符,则使用第一个添加Tab的方法,否则,用第二种。Control_Test和TestModel分别是UserControl和其ViewModel。

     1          /// <summary>
     2         /// 打开方法
     3         /// </summary>
     4         /// <param name="MenuName"></param>
     5         private void OpenMenu(string MenuName)
     6         {
     7             foreach (System.Windows.Window win in System.Windows.Application.Current.Windows)
     8             {
     9                 if (win.Name == "MainView_View")
    10                 {
    11                     if (MenuName.Contains("测试"))
    12                     {
    13                         (win.DataContext as MainViewModel).OpenNewItem<UserControls.Control_Test, UserControls.TestModel>(MenuName, MenuName);
    14                     }
    15                     else
    16                     {
    17                         UserControls.TestModelSec m = new UserControls.TestModelSec(MenuName);
    18                         (win.DataContext as MainViewModel).OpenNewItemPara<UserControls.Control_Test>(MenuName, MenuName, m);
    19                     }
    20                     break;
    21                 }
    22             }
    23         }

      初始化菜单,在“主菜单”中有四个子菜单,其中“操作”的子菜单中还有子菜单

     1         private void LoadMenuData()
     2         {
     3             MenuItem mainMenu = new MenuItem("主菜单");
     4             MenuItem projectMenu = new MenuItem("项目");
     5             MenuItem toolMenu = new MenuItem("工具");
     6             MenuItem otherMenu = new MenuItem("其他");
     7             MenuItem helpMenu = new MenuItem("帮助");
     8 
     9             mainMenu.Childrens.Add(new MenuItem("打开"));
    10             mainMenu.Childrens.Add(new MenuItem("新建"));
    11 
    12             MenuItem operateMenu = new MenuItem("操作");
    13 
    14 
    15             MenuItem saveMenu = new MenuItem("保存");
    16             MenuItem deleteMenu = new MenuItem("删除");
    17             MenuItem readMenu = new MenuItem("读取");
    18             operateMenu.Childrens.Add(saveMenu);
    19             operateMenu.Childrens.Add(deleteMenu);
    20             operateMenu.Childrens.Add(readMenu);
    21 
    22             mainMenu.Childrens.Add(operateMenu);
    23 
    24             mainMenu.Childrens.Add(new MenuItem("测试三"));
    25 
    26             helpMenu.Childrens.Add(new MenuItem("测试一"));
    27             helpMenu.Childrens.Add(new MenuItem("测试二"));
    28             helpMenu.Childrens.Add(new MenuItem("测试三"));
    29 
    30             MenuList.Add(mainMenu);
    31             MenuList.Add(projectMenu);
    32             MenuList.Add(toolMenu);
    33             MenuList.Add(otherMenu);
    34             MenuList.Add(helpMenu);
    35 
    36             SetMenuCommand(MenuList);
    37         }

      在构造中,执行初始化菜单的方法

    1 public MenuControlModel()
    2         {
    3             LoadMenuData();
    4         }

    结束

      Tab每项的内容必须为UserControl,UserControl无需与Model进行banding。测试的UserControl和其Model没有写,只是一个简单的例子~

  • 相关阅读:
    JS DOM2级事件兼容处理
    JS DOM2级事件基础
    JS 事件基础
    JS 动态规划 LeetCode 一和零
    JS 动态规划入门
    JS 动画优化 代码篇
    LeetCode笔记整理1 摩尔投票法
    LeetCode笔记整理3 二叉树中序遍历 Morris中序遍历
    java面向对象编程——第四章 类和对象
    java面向对象编程——第六章 数组
  • 原文地址:https://www.cnblogs.com/shadow-fei/p/4674048.html
Copyright © 2011-2022 走看看