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

  定义添加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         }

  别忘了,在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     }

  在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>

  定义菜单的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没有写,只是一个简单的例子~

时间: 2024-08-03 19:03:54

WPF-菜单和Tab控件的相关文章

Zara带你快速入门WPF(4)---菜单与功能区控件

前言:许多数据驱动的应用程序都包含菜单和工具栏或功能区控件,允许用户控制操作,在WPF中,也可以使用功能区控件,所以这里介绍菜单和功能区控件. 一.菜单控件 在WPF中,菜单很容易使用Menu和MenuItem元素创建,如下面代码,其中一个主菜单和一个次菜单,以及一个子菜单项列表. <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presen

WPF Step By Step 控件介绍

WPF Step By Step 控件介绍 回顾 上一篇,我们主要讨论了WPF的几个重点的基本知识的介绍,本篇,我们将会简单的介绍几个基本控件的简单用法,本文会举几个项目中的具体的例子,结合这些 例子,希望我们可以对WPF的掌握会更深刻.本文涉及的内容可能较多.请大家慢慢看看.错误之处,还请指出. 本文大纲 1.基本控件介绍与用法. 基本控件介绍与用法 文本控件 Label控件 label控件:一般用户描述性文字显示. 在Label控件使用时,一般给予用户提示.用法上没有什么很特殊的,label

我的开源框架之TAB控件

需求 (1)支持iframe.html.json格式的tab内容远程请求 (2)支持动态添加tab (3)支持远程加载完成监听,支持tab激活事件监听 (4)支持reload tab内容[如果是远程加载] (5)支持邮件菜单[未实现] 实现图例 客户代码 1 <body> 2 <div id="text"> 3 <h3>无题</h3> 4 <p>月落湖面两清影,</p> 5 <p>岸柳丝丝弄轻盈.<

WPF后台设置xaml控件的样式System.Windows.Style

WPF后台设置xaml控件的样式System.Windows.Style 摘-自 :感谢 作者: IT小兵   http://3w.suchso.com/projecteac-tual/wpf-zhishi-houtai-shezhi-style.html Style myStyle = (Style)this.FindResource("TabItemStyle");//TabItemStyle 这个样式是引用的资源文件中的样式名称 静态资源在第一次编译后即确定其对象或值,之后不能对

WPF 中动态改变控件模板

在某些项目中,可能需要动态的改变控件的模板,例如软件中可以选择不同的主题,在不同的主题下软件界面.控件的样式都会有所不同,这时即可通过改变控件模板的方式实现期望的功能. 基本方法是当用户点击切换主题按钮是加载新的资源字典,并使用新加载的资源字典替代当前的资源字典这时要用到ResourceManager. 假设现有两个不同的资源字典文件Dictionary1.xaml和Dictionary2.xaml存在于Themes文件夹内: 在MainPage中使用其中一个资源字典作为默认样式文件: <Win

终于知道如何使Tab控件的不出现白边的方法了

如下图,在棋盘右侧添加了Tab控件,做成属性页的样子,但出现了白边,很不美观: 后来发现,需要把Tab空间的Owner Draw Fixed 设置为TRUE.但问题又来了,属性页上的标题文字不显示了,结果如图: 继续搜索,原来需要CTabCtrl的DrawItem函数,事实上MFC是强制要求重载的,实际操作过程如下: void CMyTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct){ //获取选项卡文字内容 TCHAR szTabText[

WPF利用通过父控件属性来获得绑定数据源RelativeSource

WPF利用通过父控件属性来获得绑定数据源RelativeSource 有时候我们不确定作为数据源的对象叫什么名字,但知道作为绑定源与UI布局有相对的关系,如下是一段XAML代码,说明多层布局控件中放置一个文本控件,来显示父级控件的名称. 1.XAML Html代码 <Grid x:Name="g1" Background="Red" Margin="10"> <DockPanel x:Name="d1" Ba

高质量的基于向量条形码产生机制 WPF Drawing API条形码控件

Barcode Professional for WPF条形码控件是一款轻量级的 .NET 程序集,为你的WPF程序生成高质量的基于矢量的条码,支持大多数流行的一维和二维条形码:Code 39, Code 128, GS1-128, GS1 DataBar (RSS-14),  EAN 13 & UPC, Postal (USPS, British Royal Mail, Australia Post, DHL, etc.), Data Matrix, QR Code, PDF 417, UPS

Wpf使用Winform控件后Wpf元素被Winform控件遮盖问题的解决

有人会说不建议Wpf中使用Winform控件,有人会说建议使用Winform控件在Wpf下的替代方案,然而在实际工作中由于项目的特殊需求,考虑到时间.成本等因素,往往难免会碰到在WPF中使用Winfrom控件的问题,我们知道Wpf可以通过使用WindowsFormsHost容器调用Winform控件,但是在一些场合需要将Wpf元素显示在Winform控件的上层,此时就会出现Wpf元素被Winform控件遮盖的问题. 一.场景再现 接到公司命令,在时间紧迫的情况下,需要将原来的Winform程序(