原文:Prism for WPF 搭建一个简单的模块化开发框架(三) 给TreeView加样式做成菜单

昨天晚上把TreeView的样式做了一下,今天给TreeView绑了数据,实现了切换页面功能

上代码把,样式代码

  1. <Style x:Key="MenuTreeViewItem" TargetType="{x:Type TreeViewItem}">
  2. <Style.Triggers>
  3. <Trigger Property="IsSelected" Value="True">
  4. <Setter Property="FontWeight" Value="Bold" />
  5. </Trigger>
  6. </Style.Triggers>
  7. <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
  8. <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
  9. <Setter Property="MinHeight" Value="40" />
  10. <Setter Property="Foreground" Value="White" />
  11. <Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.BackgroundBrush}" />
  12. <Setter Property="BorderBrush" Value="{DynamicResource Sys.TreeViewItem.BorderBrush}" />
  13. <Setter Property="BorderThickness" Value="0,0,0,1" />
  14. <Setter Property="SnapsToDevicePixels" Value="True" />
  15. <Setter Property="Margin" Value="0" />
  16. <Setter Property="FontSize" Value="20"/>
  17. <Setter Property="Template">
  18. <Setter.Value>
  19. <ControlTemplate TargetType="{x:Type TreeViewItem}">
  20. <StackPanel>
  21. <Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
  22. BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"
  23. MinHeight="{TemplateBinding MinHeight}" UseLayoutRounding="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
  24. <Grid Margin="{TemplateBinding Margin}" VerticalAlignment="Stretch" >
  25. <Grid.ColumnDefinitions>
  26. <ColumnDefinition MinWidth="18" Width="Auto" />
  27. <ColumnDefinition Width="*" />
  28. <ColumnDefinition Width="21"/>
  29. </Grid.ColumnDefinitions>
  30. <!--图标Text="" -->
  31. <TextBlock x:Name="ItemIcon" Text="{Binding itemIcon}" Foreground="{TemplateBinding Foreground}" FontSize="13" Margin="4" Height="13" VerticalAlignment="Center" Style="{DynamicResource FIcon}"/>
  32. <!--展开收缩按钮-->
  33. <ToggleButton x:Name="ExpanderBtn" Grid.Column="2"
  34. IsChecked="{Binding Path=IsExpanded, RelativeSource={x:Static RelativeSource.TemplatedParent}, Mode=TwoWay}"
  35. ClickMode="Press" >
  36. <ToggleButton.Template>
  37. <ControlTemplate TargetType="ToggleButton">
  38. <Border>
  39. <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
  40. </Border>
  41. </ControlTemplate>
  42. </ToggleButton.Template>
  43. <ToggleButton.Content>
  44. <TextBlock x:Name="ExpanderIcon" Foreground="{TemplateBinding Foreground}" FontSize="13" Margin="4" Height="15" VerticalAlignment="Center" Text="" Style="{DynamicResource FIcon}"/>
  45. </ToggleButton.Content>
  46. </ToggleButton>
  47. <!--内容-->
  48. <ContentPresenter x:Name="PART_Header" Grid.Column="1" ContentSource="Header"
  49. SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
  50. HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
  51. VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
  52. </Grid>
  53. </Border>
  54. <ItemsPresenter Margin="5,0,0,0" x:Name="ItemsHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
  55. </StackPanel>
  56. <ControlTemplate.Triggers>
  57. <Trigger Property="IsExpanded" Value="False">
  58. <Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
  59. </Trigger>
  60. <Trigger Property="IsExpanded" Value="True">
  61. <Setter TargetName="ExpanderIcon" Property="Text" Value="" />
  62. </Trigger>
  63. <Trigger Property="HasItems" Value="False">
  64. <Setter TargetName="ExpanderIcon" Property="Visibility" Value="Hidden" />
  65. </Trigger>
  66. <Trigger Property="IsMouseOver" Value="True">
  67. <Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.MouseOver.BackgroundBrush}" />
  68. <Setter Property="Foreground" Value="{DynamicResource Sys.TreeViewItem.MouseOver.Foreground}" />
  69. </Trigger>
  70. <Trigger Property="IsSelected" Value="True">
  71. <Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.MouseOver.BackgroundBrush}" />
  72. <Setter Property="Foreground" Value="{DynamicResource Sys.TreeViewItem.MouseOver.Foreground}" />
  73. </Trigger>
  74. <MultiTrigger>
  75. <MultiTrigger.Conditions>
  76. <Condition Property="IsSelected" Value="True" />
  77. <Condition Property="Selector.IsSelectionActive" Value="True" />
  78. </MultiTrigger.Conditions>
  79. <Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.MouseOver.BackgroundBrush}" />
  80. <Setter Property="Foreground" Value="{DynamicResource Sys.TreeViewItem.MouseOver.Foreground}" />
  81. </MultiTrigger>
  82. </ControlTemplate.Triggers>
  83. </ControlTemplate>
  84. </Setter.Value>
  85. </Setter>
  86. </Style>
  87. <!--TreeView样式-->
  88. <Style x:Key="MenuTreeView" TargetType="{x:Type TreeView}">
  89. <Setter Property="ScrollViewer.CanContentScroll" Value="True" />
  90. <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"></Setter>
  91. <Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" />
  92. <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
  93. <Setter Property="Background" Value="{DynamicResource Sys.TreeView.BackgroundBrush}"/>
  94. <Setter Property="BorderBrush" Value="{DynamicResource Sys.TreeView.BorderBrush}"/>
  95. <Setter Property="ItemContainerStyle" Value="{StaticResource MenuTreeViewItem}"></Setter>
  96. <Setter Property="ItemsPanel">
  97. <Setter.Value>
  98. <ItemsPanelTemplate>
  99. <VirtualizingStackPanel IsItemsHost="True" Margin="0"/>
  100. </ItemsPanelTemplate>
  101. </Setter.Value>
  102. </Setter>
  103. </Style>

这里样式就把之前的每个item显示【折叠按钮】、【文本】

改为了显示【图标】、【文本】、【折叠按钮】

出来的效果是这样的,减小了父子两级的缩进,因为父子两级都是相同的样式背景色,并没有把缩进完全去掉

做了个Border做视觉上的分割

下面实现数据绑定

实现了INotifyPropertyChanged接口,一不小心就用上了传说中的MVVM模式?

Model代码

  1. public class MenuViewModel : INotifyPropertyChanged
  2. {
  3. private ObservableCollection<ItemTreeData> itemTreeDataList = new ObservableCollection<ItemTreeData>();
  4. public ObservableCollection<ItemTreeData> ItemTreeDataList
  5. {
  6. get { return itemTreeDataList; }
  7. set
  8. {
  9. itemTreeDataList = value;
  10. NotifyPropertyChanged("ItemTreeDataList");
  11. }
  12. }
  13. public event PropertyChangedEventHandler PropertyChanged;
  14. public void NotifyPropertyChanged(String propertyName)
  15. {
  16. if (this.PropertyChanged != null)
  17. this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  18. }
  19. }
  20. public class ItemTreeData // 自定义Item的树形结构
  21. {
  22. public int itemId { get; set; } // ID
  23. public string itemName { get; set; } // 名称
  24. public string itemView { get; set; }
  25. public string itemRegion { get; set; }
  26. public string itemIcon { get; set; } //
  27. private ObservableCollection<ItemTreeData> _children = new ObservableCollection<ItemTreeData>();
  28. public ObservableCollection<ItemTreeData> Children
  29. { // 树形结构的下一级列表
  30. get
  31. {
  32. return _children;
  33. }
  34. set
  35. {
  36. _children = value;
  37. }
  38. }
  39. public bool IsExpanded { get; set; } // 节点是否展开
  40. public bool IsSelected { get; set; } // 节点是否选中
  41. }

组装数据是在个模块的IModule接口下做的,先随意写点数据,itemName就是菜单的显示文本,itemView是要导航的页面,

如果又需要,可以做参数的属性,Prism的导航也是支持传参的

  1. public void Initialize()
  2. {
  3. ObservableCollection<ItemTreeData> chi = new ObservableCollection<ItemTreeData>();
  4. chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map1", itemIcon = "\xe63c", itemRegion = RegionNames.Map, itemView = "View1" });
  5. chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map2", itemIcon = "\xe63c", itemRegion = RegionNames.Map, itemView = "View2" });
  6. chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map3", itemIcon = "\xe63c" });
  7. chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map4", itemIcon = "\xe63c" });
  8. chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map5", itemIcon = "\xe63c" });
  9. MenuViewModel vm = new MenuViewModel();
  10. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe63c", Children = chi });
  11. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "地图显示", itemIcon = "\xe63c" });
  12. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe62f" });
  13. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
  14. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
  15. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
  16. vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
  17. GlobalData.NavModules.Add(new NavModuleInfo() {
  18. region = RegionNames.Main,
  19. module = ModuleNames.Map,
  20. title = ModuleTitle.Map,
  21. icon = "\xe63c",
  22. img = Images.CreateImageSourceFromImage(Properties.Resources.avtar),
  23. menuVm = vm
  24. });
  25. this.moduleTracker.RecordModuleInitialized(ModuleNames.Map);
  26. regionManager.RegisterViewWithRegion(RegionNames.Main, typeof(MapModule_MainView));
  27. }

数据有了,样式有了,下面该关联起来了,其实这步很简单了

在菜单页面订阅一个导航切换的事件,每当模块发生改变时,加载新的模块的菜单数据

这里主要用到Prism的IEventAggregator实现模块之间的通信

  1. [ImportingConstructor]
  2. public MenuView(IRegionManager regionManager, IEventAggregator eventAggregator, IModuleManager moduleManager)
  3. {
  4. this.eventAggregator = eventAggregator;
  5. //ChangeModuleToMenuEvent cmtmEvent = this.eventAggregator.GetEvent<ChangeModuleToMenuEvent>();
  6. ////这里订阅一个改变模块的事件,模块改变时修改menu
  7. //cmtmEvent.Subscribe(OnChangeModuleEvent);
  8. NavigateToScreenEvent ntsEvent = GlobalData.EventAggregator.GetEvent<NavigateToScreenEvent>();
  9. ntsEvent.Subscribe(OnLinkageNavigateEvent);
  10. HNavigateToScreenEvent hntsEvent = GlobalData.EventAggregator.GetEvent<HNavigateToScreenEvent>();
  11. hntsEvent.Subscribe(OnLinkageHNavigateEvent);
  12. }
  13. public void OnLinkageNavigateEvent(CommandRegionEventArgs e)
  14. {
  15. if (_contentLoaded)
  16. {
  17. LayoutRoot.DataContext = e.menuVm;
  18. }
  19. else {
  20. menuVm = e.menuVm;
  21. }
  22. }

基础的东西都准备好了,现在就算见证奇迹的时刻了,

再加两句代码,在SelectedItemChanged的时候做页面导航

  1. private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
  2. {
  3. ItemTreeData treeData = (ItemTreeData)treeView.SelectedItem;
  4. if (treeData!=null && !string.IsNullOrEmpty(treeData.itemRegion) && !string.IsNullOrEmpty(treeData.itemView))
  5. {
  6. regionManager.RequestNavigate(treeData.itemRegion, treeData.itemView);
  7. }
  8. }

导航这块没遇到啥坑,也就不记录了,

哎,基础差,知识少,理解浅。难得这么顺畅

 

总感觉有些显得小气,分辨率太高 1920*1080?比例分布不均匀?

现在看这大红色儿太刺眼了

到这里框架前台部分基本上已经成型了,后面应该就算调调样式,考虑一下数据怎么取,直接取还是service?还是wcf?

拿什么做服务?现在不都讲究跨平台吗?服务这块最好是拿出来做一个手机或者网页,或者客户端都能用的

 

 

Prism for WPF 搭建一个简单的模块化开发框架(三) 给TreeView加样式做成菜单的更多相关文章

  1. Prism for WPF 搭建一个简单的模块化开发框架 (一个节点)

    原文:Prism for WPF 搭建一个简单的模块化开发框架 (一个节点) 这里我就只贴图不贴代码了,看看这个节点之前的效果 觉得做的好的地方可以范之前的文章看看 有好的建议也可以说说   填充数据 ...

  2. Prism for WPF 搭建一个简单的模块化开发框架(六)隐藏菜单、导航

    原文:Prism for WPF 搭建一个简单的模块化开发框架(六)隐藏菜单.导航 这个实际上是在聊天之前做的,一起写了,也不分先后了 看一下效果图,上面是模块主导航,左侧是模块内菜单,现在加一下隐藏 ...

  3. Prism for WPF 搭建一个简单的模块化开发框架(四)异步调用WCF服务、WCF消息头添加安全验证Token

    原文:Prism for WPF 搭建一个简单的模块化开发框架(四)异步调用WCF服务.WCF消息头添加安全验证Token 为什么选择wcf?   因为好像wcf和wpf就是哥俩,,, 为什么选择异步 ...

  4. Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天、消息模块

    原文:Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天.消息模块 中秋节假期没事继续搞了搞 做了各聊天的模块,需要继续优化 第一步画页面 页面参考https://github.c ...

  5. Prism for WPF 搭建一个简单的模块化开发框架(二)

    原文:Prism for WPF 搭建一个简单的模块化开发框架(二) 今天又有时间了,再改改,加了一些控件全局的样式 样式代码 <ResourceDictionary xmlns="h ...

  6. Prism for WPF 搭建一个简单的模块化开发框架(一)

    原文:Prism for WPF 搭建一个简单的模块化开发框架(一) 最近闲来无事又想搞搞WPF..... 做个框架吧,可能又是半途而废....总是坚持不下来 不废话了, 先看一下工程结构 布局大概是 ...

  7. 用express搭建一个简单的博客系统

    转自:https://blog.csdn.net/qq_29721837/article/details/62055603 Express 简介 Express 是一个简洁而灵活的 node.js W ...

  8. 从零开始搭建一个简单的基于webpack的vue开发环境

    原文地址:https://segmentfault.com/a/1190000012789253?utm_source=tag-newest 从零开始搭建一个简单的基于webpack的react开发环 ...

  9. 用nodejs搭建一个简单的服务器

    使用nodejs搭建一个简单的服务器 nodejs优点:性能高(读写文件) 数据操作能力强 官网:www.nodejs.org 验证是否安装成功:cmd命令行中输入node -v 如果显示版本号表示安 ...

随机推荐

  1. 漫谈 Clustering (4): Spectral Clustering

    转:http://blog.pluskid.org/?p=287 如果说 K-means 和 GMM 这些聚类的方法是古代流行的算法的话,那么这次要讲的 Spectral Clustering 就可以 ...

  2. Topic model的变种及其应用[1]

    转: http://www.blogbus.com/krischow-logs/65749376.html   LDA 着实 带领着 Topic model 火了一把. 但是其实我们华人世界内,也不乏 ...

  3. QT信号和槽在哪个线程执行问题

    时隔四个月后的第一篇,换了个公司可以登录的博客,记录一些学习内容吧 这是看到别人写的比较好的一篇,排版有点乱 QThread的使用方法 起源 昨天不小心看到Qt开发人员( Bradley T.Hugh ...

  4. 显示锁(ReentranLock)

    1. Lock接口:定义了一组抽象的加锁操作,提供了一种无条件的.可轮询的.定时的以及可中断的锁获取操作,所有的加锁和解锁的方法都是显示的. 2. ReentrantLock锁:实现了Lock接口,并 ...

  5. Python解析配置文件模块:ConfigPhaser

    算是前几周落下的博客补一篇.介绍一下python中如何解析配置文件.配置文件常用的几种格式:xml,json,还有ini.其中ini算是最简单的一种格式,因为小,解析的速度也要比xml和json快(并 ...

  6. Hibernate之openSession与getCurrentSession的区别

    openSession 与 getCurrentSession的区别(1)openSession 每一次获得的是一个全新的session对象,而getCurrentSession获得的是与当前线程绑定 ...

  7. HTTP缓存机制--客户端缓存(转)

    客户端缓存 客户端侧缓存一般指的是浏览器缓存,目的就是加速各种静态资源的访问,想想现在的大型网站,随便一个页面都是一两百个请求,每天 pv 都是亿级别,如果没有缓存,用户体验会急剧下降.同时服务器压力 ...

  8. php面试重要知识点,面试题

    1.什么是引用变量,用什么符号定义引用变量? 概念:用不同的名称引用同一个变量的内容:用&符号定义. 例如: $a = range(0,100); $b = &$a; $b = ran ...

  9. [转载] iOS应用程序的生命周期

    iOS应用程序的生命周期 2015-06-23 iOS大全 (点击上方蓝字,快速关注我们) iOS应用程序一般都是由自己编写的代码和系统框架(system frameworks)组成,系统框架提供一些 ...

  10. LeetCode28.实现strStr() JavaScript

    实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...