一、页面添加TreeView和TabControl控件

1.在MainWindow.xaml页面上添加TreeView控件,设置ItemsSource属性为ViewModel中的TreeList属性,添加<TreeView.ItemTemplate>,在该节点下添加<HierarchicalDataTemplate>,绑定ViewModel中的Tree List下子项中的Children属性,菜单名称绑定Header属性

 1 <TreeView Background="Transparent" BorderThickness="0" ItemsSource="{Binding TreeList}">
 2     <TreeView.ItemTemplate>
 3         <HierarchicalDataTemplate ItemsSource="{Binding Children}">
 4             <Grid>
 5                 <Grid.ColumnDefinitions>
 6                     <ColumnDefinition Width="30" Name="c1"/>
 7                     <ColumnDefinition/>
 8                 </Grid.ColumnDefinitions>
 9                 <TextBlock Text="{Binding IconCode}"  
10                           FontFamily="{StaticResource Iconfont}"
11                           VerticalAlignment="Center" 
12                           HorizontalAlignment="Center"
13                           FontSize="18" 
14                           SnapsToDevicePixels="True"/>
15 
16                 <TextBlock Text="{Binding Header}" Grid.Column="1" Margin="5,0,0,0" FontSize="13"/>
17             </Grid>
18             <HierarchicalDataTemplate.Triggers>
19                 <DataTrigger Binding="{Binding IconCode}" Value="{x:Null}">
20                     <Setter TargetName="c1" Property="Width" Value="13"/>
21                 </DataTrigger>
22             </HierarchicalDataTemplate.Triggers>
23         </HierarchicalDataTemplate>
24     </TreeView.ItemTemplate>
25 </TreeView>
View Code

在<Window.Resources>资源文件中设置style样式,TargetType为TreeViewItem,并设置样式背景等属性

  设置Template属性ControlTemplate,TargetType为TreeViewItem,

 1         <Style TargetType="TreeViewItem">
 2             <Setter Property="IsExpanded" Value="{Binding IsExpanded,Mode=TwoWay}"/>
 3             <Setter Property="Background" Value="Transparent"/>
 4             <Setter Property="HorizontalContentAlignment" Value="Left"/>
 5             <Setter Property="VerticalContentAlignment" Value="Center"/>
 6             <Setter Property="Padding" Value="8,5"/>
 7             <Setter Property="Foreground" Value="White"/>
 8             <Setter Property="FontSize" Value="12"/>
 9             <Setter Property="BorderThickness" Value="0"/>
10             <Setter Property="Template">
11                 <Setter.Value>
12                     <ControlTemplate TargetType="TreeViewItem">
13                         <Grid Background="Transparent" Name="root">
14                             <Grid.ColumnDefinitions>
15                                 <ColumnDefinition/>
16                                 <ColumnDefinition MaxWidth="30"/>
17                             </Grid.ColumnDefinitions>
18                             <Grid.RowDefinitions>
19                                 <RowDefinition Height="Auto" MinHeight="36"/>
20                                 <RowDefinition  />
21                             </Grid.RowDefinitions>
22                             <!--响应当前节点的鼠标双击动作,并且关联到VM中的命令-->
23                             <Grid.InputBindings>
24                                 <MouseBinding MouseAction="LeftClick"
25                                              Command="{Binding OpenViewCommand}"
26                                              CommandParameter="{Binding}"/>
27                             </Grid.InputBindings>
28 
29                             <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}"
30                                                BorderThickness="{TemplateBinding BorderThickness}"
31                                                Background="{TemplateBinding Background}"
32                                                CornerRadius="0" Grid.ColumnSpan="2" 
33                                    Padding="{TemplateBinding Padding}"
34                                                SnapsToDevicePixels="true"
35                                    TextBlock.Foreground="{TemplateBinding Foreground}">
36                                 <ContentPresenter x:Name="PART_Header" 
37                                                  ContentSource="Header"
38                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
39                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
40                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
41                                 </ContentPresenter>
42                             </Border>
43 
44                             <ToggleButton x:Name="Expander" Grid.Column="1" ClickMode="Press" Foreground="{Binding ElementName=Bd,Path=(TextBlock.Foreground)}"
45                                          IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"
46                                          Template="{StaticResource ArrowButtonTemplate}"/>
47                             <!--当前子项的  Children集合-->
48                             <ItemsPresenter x:Name="ItemsHost" Margin="18,0,0,0" Grid.ColumnSpan="2" Grid.Row="1" />
49                         </Grid>
50 
51                         <ControlTemplate.Triggers>
52                             <Trigger Property="IsExpanded" Value="false">
53                                 <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
54                             </Trigger>
55                             <DataTrigger Binding="{Binding Children.Count}" Value="0">
56                                 <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
57                             </DataTrigger>
58                             <Trigger Property="IsSelected" Value="true">
59                                 <Setter Property="Background" TargetName="Bd" Value="#F7F9FA"/>
60                                 <Setter Property="Foreground" Value="#0b3d90"/>
61                                 <Setter Property="Foreground" Value="#0b3d90" TargetName="Expander"/>
62                             </Trigger>
63                         </ControlTemplate.Triggers>
64                     </ControlTemplate>
65                 </Setter.Value>
66             </Setter>
67         </Style>
View Code

2.增加TabControl控件,设置相关属性;在TabControl控件下增加子节点<TabControl.ItemContainerStyle>,<TabControl.ItemTemplate >文本标题,<TabControl.ContentTemplate>页面内容

 1 <TabControl x:Name="TabControlItem" 
 2             Grid.Row="1" 
 3             ItemsSource="{Binding Pages}" 
 4             SelectionChanged="TabControlItem_SelectionChanged"
 5             Background="Transparent" 
 6             BorderThickness="0,1,0,0" 
 7             BorderBrush="White">
 8     <TabControl.ItemContainerStyle>
 9         <Style TargetType="TabItem">
10             <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
11             <Setter Property="Background" Value="#336590C1"/>
12             <Setter Property="Margin" Value="2,0"/>
13             <Setter Property="Foreground" Value="#777"/>
14             <Setter Property="Template">
15                 <Setter.Value>
16                     <!--控件模板-->
17                     <ControlTemplate TargetType="TabItem">
18                         <Grid Background="{TemplateBinding Background}" Height="30">
19                             <Grid.ColumnDefinitions>
20                                 <ColumnDefinition/>
21                                 <ColumnDefinition Width="auto" MinWidth="10"/>
22                             </Grid.ColumnDefinitions>
23                             <ContentPresenter ContentSource="Header" VerticalAlignment="Center" Margin="10,5,5,5"/>
24                             <Grid Grid.Column="1" Width="30" Margin="0,0,3,0">
25                                 <Button Grid.Column="1" 
26                                         Style="{StaticResource TabCloseButtonStyle}" 
27                                         Foreground="{TemplateBinding Foreground}" 
28                                         Margin="3,0"
29                                         Command="{Binding CloseTabCommand}"
30                                         CommandParameter="{Binding}"/>
31                             </Grid>
32                         </Grid>
33                     </ControlTemplate>
34                 </Setter.Value>
35             </Setter>
36             <Style.Triggers>
37                 <Trigger Property="IsMouseOver" Value="True">
38                     <Setter Property="Background" Value="#EEE"/>
39                 </Trigger>
40                 <Trigger Property="IsSelected" Value="True">
41                     <Setter Property="Background" Value="#FF6590C1"/>
42                     <Setter Property="Foreground" Value="#FFDEFBFF"/>
43                 </Trigger>
44             </Style.Triggers>
45         </Style>
46     </TabControl.ItemContainerStyle>
47     <!--Header部分-->
48     <TabControl.ItemTemplate >
49         <!--数据模板-->
50         <DataTemplate>
51             <TextBlock  Text="{Binding Header}"/>
52         </DataTemplate>
53     </TabControl.ItemTemplate>
54     <!--内容部分-->
55     <TabControl.ContentTemplate>
56         <!--数据模板-->
57         <DataTemplate>
58             <ContentControl Content="{Binding PageView}"/>
59         </DataTemplate>
60     </TabControl.ContentTemplate>
61 </TabControl>
View Code

 

二、封装ViewModel中属性双向绑定通知,命令事件,页面方法注入管理等基类

1、页面方法注入管理类ActionManager,View中的行为方法存放进来,由窗口对象调用 ,注册一个方法,这个方法中有打开弹窗的逻辑

 1     /// <summary>
 2     /// 页面方法注入管理类
 3     /// </summary>
 4     public class ActionManager
 5     {
 6         // 委托
 7         static Dictionary<string, Delegate> actionMap = new Dictionary<string, Delegate>();
 8 
 9         // 希望能将View中的行为方法存放进来   注册
10         // 由窗口对象调用 ,注册一个方法,这个方法中有打开弹窗的逻辑
11         // 优化:由不同实例进行注册的时候  进行区分
12         // 这个方法可以让我们接受两种类型的委托对象  Action  Func
13         public static void Register(string key, Delegate action)
14         {
15             if (!actionMap.ContainsKey(key))
16                 actionMap.Add(key, action);
17         }
18 
19         // VM中需要进行调用
20         public static void Execute(string key, object data)
21         {
22             if (actionMap.ContainsKey(key))
23                 actionMap[key].DynamicInvoke(data);
24         }
25 
26         public static bool ExecuteAndResult(string key, object data)
27         {
28             if (actionMap.ContainsKey(key))
29             {
30                 var action = (actionMap[key] as Func<object, bool>);
31                 if (action == null)
32                     return false;
33 
34                 return action.Invoke(data);
35             }
36             return false;
37         }
38 
39         public static void Unregister(string key)
40         {
41 
42         }
43     }
View Code

2.通知基础类NotifyBase,继承自接口INotifyPropertyChanged(using System.ComponentModel)

 1     /// <summary>
 2     /// 通知基础类
 3     /// </summary>
 4     public class NotifyBase : INotifyPropertyChanged
 5     {
 6         public event PropertyChangedEventHandler? PropertyChanged;
 7 
 8         public void SetProperty<T>(ref T field, T value, [CallerMemberName] string propName = "")
 9         {
10             if (field == null || !field.Equals(value))
11             {
12                 field = value;
13                 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
14             }
15         }
16     }
View Code

3.命令方法基础类Command<T> ,继承自接口ICommand(using System.Windows.Input),封装委托方法的执行

 1     /// <summary>
 2     /// 命令方法基础类
 3     /// </summary>
 4     /// <typeparam name="T"></typeparam>
 5     public class Command<T> : ICommand
 6     {
 7         public event EventHandler? CanExecuteChanged;
 8 
 9         public bool CanExecute(object? parameter)
10         {
11             if (DoCanExecute == null) return true;
12             return DoCanExecute(parameter);
13         }
14 
15 
16         public void Execute(object? parameter)
17         {
18             DoExecuteNoneParam?.Invoke();
19 
20             dynamic p = parameter;
21             DoExecuteWithParam?.Invoke(p);
22         }
23 
24         public void RasieCanExecuteChanged()
25         {
26             CanExecuteChanged?.Invoke(this, new EventArgs());
27         }
28 
29 
30         public Action DoExecuteNoneParam { get; set; }
31         public Action<T> DoExecuteWithParam { get; set; }
32 
33 
34         public Func<object, bool> DoCanExecute { get; set; }
35 
36         /// <summary>
37         /// 
38         /// </summary>
39         /// <param name="doExecute"></param>
40         public Command(Action doExecute)
41         {
42             DoExecuteNoneParam = doExecute;
43         }
44 
45         /// <summary>
46         /// 
47         /// </summary>
48         /// <param name="doExecute"></param>
49         public Command(Action<T> doExecute)
50         {
51             DoExecuteWithParam = doExecute;
52         }
53 
54         //public Command(Action<int?> executePageUpdatedCommand)
55         //{
56         //   // DoExecuteNoneParam = executePageUpdatedCommand;
57         //}
58     }
View Code

 

三、ViewModel方法的编写和绑定,实现页面中绑定的命令方法,和属性,list数据获取

1.菜单类MenuItemModel

 1     /// <summary>
 2     /// 菜单
 3     /// </summary>
 4     public class MenuItemModel
 5     {
 6         public int Id { get; set; }
 7         public int Parent { get; set; }
 8         public string? IconCode { get; set; }
 9         public string? Header { get; set; }
10         public string? TargetView { get; set; }
11 
12         public ICommand? OpenViewCommand { get; set; }
13 
14         public List<MenuItemModel> Children { get; set; } = new List<MenuItemModel>();
15 
16     }
View Code

2.页面类PageItemModel,继承基类NotifyBase,实现属性的双向绑定,更新保存等

 1     public class PageItemModel : NotifyBase
 2     {
 3         private bool _isSelected;
 4         public bool IsSelected
 5         {
 6             get { return _isSelected; }
 7             set { SetProperty(ref _isSelected, value); }
 8         }
 9         public string Header { get; set; }
10         public object PageView { get; set; }
11 
12         public ICommand CloseTabCommand { get; set; }
13 
14         public int Parent { get; set; }
15     }
View Code

3.MainViewModel,继承基类NotifyBase,实现属性的双向绑定,更新保存等

  封装打开菜单的方法,通过反射找到菜单对应的页面,页面为dll.文件夹.页面名称的格式

  
 1         /// <summary>
 2         /// 打开选择菜单项
 3         /// </summary>
 4         /// <param name="menu"></param>
 5         private void OpenView(MenuItemModel menu)
 6         {
 7             var page = Pages.ToList().FirstOrDefault(p => p.Header == menu.Header);
 8 
 9             if (page == null)
10             {
11                 Type type = Assembly.GetExecutingAssembly().GetType(menu.TargetView);
12                 object p = Activator.CreateInstance(type);
13 
14                 Pages.Add(new PageItemModel
15                 {
16                     Parent = menu.Parent,
17                     Header = menu.Header,
18                     PageView = p,
19                     IsSelected = true,
20                     CloseTabCommand = new Command<PageItemModel>(ClosePage)
21                 });
22 
23                 this.MenuSecondHeader = menu.Header;
24             }
25             else
26                 page.IsSelected = true;
27         }
View Code  

  页面 集合
    public ObservableCollection<PageItemModel> Pages { get; set; } = new ObservableCollection<PageItemModel>();

完整代码

  1 public class MainViewModel : NotifyBase
  2 {
  3     // 菜单 集合
  4     public List<MenuItemModel> TreeList { get; set; }
  5     // 页面 集合
  6     public ObservableCollection<PageItemModel> Pages { get; set; }
  7         = new ObservableCollection<PageItemModel>();
  8 
  9     //内容标题一级菜单
 10    // public ObservableCollection<string> MenuFirstHeader { get; set; }
 11 
 12     //内容标题二级菜单
 13     private string _menuSecondHeader;
 14     public string MenuSecondHeader
 15     {
 16         get { return _menuSecondHeader; }
 17         set
 18         {
 19             _menuSecondHeader = value;
 20             SetProperty<string>(ref _menuSecondHeader, value);
 21         }
 22     }
 23 
 24     public MainViewModel()
 25     {
 26         //菜单初始化
 27         InitMenu();
 28     }
 29 
 30     /// <summary>
 31     /// 菜单初始化
 32     /// </summary>
 33     private void InitMenu()
 34     {
 35         #region 菜单初始化
 36         TreeList = new List<MenuItemModel>();
 37         {
 38             MenuItemModel tim = new MenuItemModel();
 39             tim.Parent = 0;
 40             tim.Id = 1;
 41             tim.Header = "工艺设计";
 42             //&#xe740;  XAML里使用
 43             tim.IconCode = "\ue610"; // 字体图标编码,阿里的Iconfont平台打包的图标库
 44             TreeList.Add(tim);
 45             MenuItemModel tim1 = new MenuItemModel();
 46             tim1.Header = "系统设置";
 47             //&#xe740;  XAML里使用
 48             tim1.IconCode = "\ue626"; // 字体图标编码,阿里的Iconfont平台打包的图标库
 49             tim1.Parent = 0;
 50             tim1.Id = 2;
 51             TreeList.Add(tim1);
 52             tim1.Children.Add(new MenuItemModel
 53             {
 54                 Parent=2,
 55                 Header = "用户管理",
 56                 TargetView = "MESWPFUI.Views.Pages.SystemSet.UserManage",
 57                 OpenViewCommand = new Command<MenuItemModel>(OpenView)
 58             });
 59             tim.Children.Add(new MenuItemModel
 60             {
 61                 Parent = 1,
 62                 Header = "加工工艺",
 63                 TargetView = "MESWPFUI.Views.Pages.BlankPage",
 64                 OpenViewCommand = new Command<MenuItemModel>(OpenView)
 65             });
 66             tim.Children.Add(new MenuItemModel
 67             {
 68                 Parent = 1,
 69                 Header = "EBOM",
 70                 TargetView = "BlankPage",
 71                 OpenViewCommand = new Command<MenuItemModel>(OpenView)
 72             });
 73             tim.Children.Add(new MenuItemModel
 74             {
 75                 Parent = 1,
 76                 IconCode = "\ue661",
 77                 Header = "设备看板",
 78                 TargetView = "MESWPFUI.Views.Pages.ProcessDesign.DevicePage",
 79                 OpenViewCommand = new Command<MenuItemModel>(OpenView)
 80             });
 81 
 82             tim.Children.Add(new MenuItemModel
 83             {
 84                 Parent = 1,
 85                 Header = "PBOM",
 86                 TargetView = "PBomPage",
 87                 OpenViewCommand = new Command<MenuItemModel>(OpenView)
 88             });
 89             MenuItemModel subMenu = new MenuItemModel();
 90             subMenu.Parent = 1;
 91             subMenu.Id = 3;
 92             subMenu.Header = "二级菜单";
 93             subMenu.Children.Add(
 94                 new MenuItemModel
 95                 {
 96                     Parent = 3,
 97                     Header = "三级菜单",
 98                     TargetView = "MESWPFUI.Views.Pages.ProcessDesign.DevicePage",
 99                     OpenViewCommand = new Command<MenuItemModel>(OpenView)
100                 }
101                );
102             tim.Children.Add(subMenu);
103         }
104         #endregion
105     }
106 
107     /// <summary>
108     /// 打开选择菜单项
109     /// </summary>
110     /// <param name="menu"></param>
111     private void OpenView(MenuItemModel menu)
112     {
113         var page = Pages.ToList().FirstOrDefault(p => p.Header == menu.Header);
114 
115         if (page == null)
116         {
117             Type type = Assembly.GetExecutingAssembly().GetType(menu.TargetView);
118             object p = Activator.CreateInstance(type);
119 
120             Pages.Add(new PageItemModel
121             {
122                 Parent = menu.Parent,
123                 Header = menu.Header,
124                 PageView = p,
125                 IsSelected = true,
126                 CloseTabCommand = new Command<PageItemModel>(ClosePage)
127             });
128 
129             this.MenuSecondHeader = menu.Header;
130         }
131         else
132             page.IsSelected = true;
133     }
134 
135     /// <summary>
136     /// 关闭菜单选项卡
137     /// </summary>
138     /// <param name="menu"></param>
139     private void ClosePage(PageItemModel menu)
140     {
141         Pages.Remove(menu);
142     }
143 }
View Code

 

posted on 2024-12-31 10:58  江渔湖  阅读(312)  评论(0)    收藏  举报