Prism for WPF 搭建一个简单的模块化开发框架(三) 给TreeView加样式做成菜单
原文:Prism for WPF 搭建一个简单的模块化开发框架(三) 给TreeView加样式做成菜单
昨天晚上把TreeView的样式做了一下,今天给TreeView绑了数据,实现了切换页面功能
上代码把,样式代码
<Style x:Key="MenuTreeViewItem" TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="MinHeight" Value="40" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.BackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource Sys.TreeViewItem.BorderBrush}" />
<Setter Property="BorderThickness" Value="0,0,0,1" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Margin" Value="0" />
<Setter Property="FontSize" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<StackPanel>
<Border x:Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}"
MinHeight="{TemplateBinding MinHeight}" UseLayoutRounding="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<Grid Margin="{TemplateBinding Margin}" VerticalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="18" Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="21"/>
</Grid.ColumnDefinitions>
<!--图标Text="" -->
<TextBlock x:Name="ItemIcon" Text="{Binding itemIcon}" Foreground="{TemplateBinding Foreground}" FontSize="13" Margin="4" Height="13" VerticalAlignment="Center" Style="{DynamicResource FIcon}"/>
<!--展开收缩按钮-->
<ToggleButton x:Name="ExpanderBtn" Grid.Column="2"
IsChecked="{Binding Path=IsExpanded, RelativeSource={x:Static RelativeSource.TemplatedParent}, Mode=TwoWay}"
ClickMode="Press" >
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border>
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</ToggleButton.Template>
<ToggleButton.Content>
<TextBlock x:Name="ExpanderIcon" Foreground="{TemplateBinding Foreground}" FontSize="13" Margin="4" Height="15" VerticalAlignment="Center" Text="" Style="{DynamicResource FIcon}"/>
</ToggleButton.Content>
</ToggleButton>
<!--内容-->
<ContentPresenter x:Name="PART_Header" Grid.Column="1" ContentSource="Header"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</Border>
<ItemsPresenter Margin="5,0,0,0" x:Name="ItemsHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="False">
<Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="IsExpanded" Value="True">
<Setter TargetName="ExpanderIcon" Property="Text" Value="" />
</Trigger>
<Trigger Property="HasItems" Value="False">
<Setter TargetName="ExpanderIcon" Property="Visibility" Value="Hidden" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.MouseOver.BackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource Sys.TreeViewItem.MouseOver.Foreground}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.MouseOver.BackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource Sys.TreeViewItem.MouseOver.Foreground}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Background" Value="{DynamicResource Sys.TreeViewItem.MouseOver.BackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource Sys.TreeViewItem.MouseOver.Foreground}" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--TreeView样式-->
<Style x:Key="MenuTreeView" TargetType="{x:Type TreeView}">
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"></Setter>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" />
<Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" />
<Setter Property="Background" Value="{DynamicResource Sys.TreeView.BackgroundBrush}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Sys.TreeView.BorderBrush}"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource MenuTreeViewItem}"></Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" Margin="0"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
这里样式就把之前的每个item显示【折叠按钮】、【文本】
改为了显示【图标】、【文本】、【折叠按钮】
出来的效果是这样的,减小了父子两级的缩进,因为父子两级都是相同的样式背景色,并没有把缩进完全去掉
做了个Border做视觉上的分割
下面实现数据绑定
实现了INotifyPropertyChanged接口,一不小心就用上了传说中的MVVM模式?
Model代码
public class MenuViewModel : INotifyPropertyChanged
{
private ObservableCollection<ItemTreeData> itemTreeDataList = new ObservableCollection<ItemTreeData>();
public ObservableCollection<ItemTreeData> ItemTreeDataList
{
get { return itemTreeDataList; }
set
{
itemTreeDataList = value;
NotifyPropertyChanged("ItemTreeDataList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(String propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ItemTreeData // 自定义Item的树形结构
{
public int itemId { get; set; } // ID
public string itemName { get; set; } // 名称
public string itemView { get; set; }
public string itemRegion { get; set; }
public string itemIcon { get; set; } //
private ObservableCollection<ItemTreeData> _children = new ObservableCollection<ItemTreeData>();
public ObservableCollection<ItemTreeData> Children
{ // 树形结构的下一级列表
get
{
return _children;
}
set
{
_children = value;
}
}
public bool IsExpanded { get; set; } // 节点是否展开
public bool IsSelected { get; set; } // 节点是否选中
}
组装数据是在个模块的IModule接口下做的,先随意写点数据,itemName就是菜单的显示文本,itemView是要导航的页面,
如果又需要,可以做参数的属性,Prism的导航也是支持传参的
public void Initialize()
{
ObservableCollection<ItemTreeData> chi = new ObservableCollection<ItemTreeData>();
chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map1", itemIcon = "\xe63c", itemRegion = RegionNames.Map, itemView = "View1" });
chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map2", itemIcon = "\xe63c", itemRegion = RegionNames.Map, itemView = "View2" });
chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map3", itemIcon = "\xe63c" });
chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map4", itemIcon = "\xe63c" });
chi.Add(new ItemTreeData() { itemId = 1, itemName = "Map5", itemIcon = "\xe63c" });
MenuViewModel vm = new MenuViewModel();
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe63c", Children = chi });
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "地图显示", itemIcon = "\xe63c" });
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe62f" });
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
vm.ItemTreeDataList.Add(new ItemTreeData() { itemId = 1, itemName = "Map", itemIcon = "\xe643" });
GlobalData.NavModules.Add(new NavModuleInfo() {
region = RegionNames.Main,
module = ModuleNames.Map,
title = ModuleTitle.Map,
icon = "\xe63c",
img = Images.CreateImageSourceFromImage(Properties.Resources.avtar),
menuVm = vm
});
this.moduleTracker.RecordModuleInitialized(ModuleNames.Map);
regionManager.RegisterViewWithRegion(RegionNames.Main, typeof(MapModule_MainView));
}
数据有了,样式有了,下面该关联起来了,其实这步很简单了
在菜单页面订阅一个导航切换的事件,每当模块发生改变时,加载新的模块的菜单数据
这里主要用到Prism的IEventAggregator实现模块之间的通信
[ImportingConstructor]
public MenuView(IRegionManager regionManager, IEventAggregator eventAggregator, IModuleManager moduleManager)
{
this.eventAggregator = eventAggregator;
//ChangeModuleToMenuEvent cmtmEvent = this.eventAggregator.GetEvent<ChangeModuleToMenuEvent>();
////这里订阅一个改变模块的事件,模块改变时修改menu
//cmtmEvent.Subscribe(OnChangeModuleEvent);
NavigateToScreenEvent ntsEvent = GlobalData.EventAggregator.GetEvent<NavigateToScreenEvent>();
ntsEvent.Subscribe(OnLinkageNavigateEvent);
HNavigateToScreenEvent hntsEvent = GlobalData.EventAggregator.GetEvent<HNavigateToScreenEvent>();
hntsEvent.Subscribe(OnLinkageHNavigateEvent);
}
public void OnLinkageNavigateEvent(CommandRegionEventArgs e)
{
if (_contentLoaded)
{
LayoutRoot.DataContext = e.menuVm;
}
else {
menuVm = e.menuVm;
}
}
基础的东西都准备好了,现在就算见证奇迹的时刻了,
再加两句代码,在SelectedItemChanged的时候做页面导航
private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
ItemTreeData treeData = (ItemTreeData)treeView.SelectedItem;
if (treeData!=null && !string.IsNullOrEmpty(treeData.itemRegion) && !string.IsNullOrEmpty(treeData.itemView))
{
regionManager.RequestNavigate(treeData.itemRegion, treeData.itemView);
}
}
导航这块没遇到啥坑,也就不记录了,
哎,基础差,知识少,理解浅。难得这么顺畅
总感觉有些显得小气,分辨率太高 1920*1080?比例分布不均匀?
现在看这大红色儿太刺眼了
到这里框架前台部分基本上已经成型了,后面应该就算调调样式,考虑一下数据怎么取,直接取还是service?还是wcf?
拿什么做服务?现在不都讲究跨平台吗?服务这块最好是拿出来做一个手机或者网页,或者客户端都能用的
Prism for WPF 搭建一个简单的模块化开发框架(三) 给TreeView加样式做成菜单的更多相关文章
- Prism for WPF 搭建一个简单的模块化开发框架 (一个节点)
原文:Prism for WPF 搭建一个简单的模块化开发框架 (一个节点) 这里我就只贴图不贴代码了,看看这个节点之前的效果 觉得做的好的地方可以范之前的文章看看 有好的建议也可以说说 填充数据 ...
- Prism for WPF 搭建一个简单的模块化开发框架(六)隐藏菜单、导航
原文:Prism for WPF 搭建一个简单的模块化开发框架(六)隐藏菜单.导航 这个实际上是在聊天之前做的,一起写了,也不分先后了 看一下效果图,上面是模块主导航,左侧是模块内菜单,现在加一下隐藏 ...
- Prism for WPF 搭建一个简单的模块化开发框架(四)异步调用WCF服务、WCF消息头添加安全验证Token
原文:Prism for WPF 搭建一个简单的模块化开发框架(四)异步调用WCF服务.WCF消息头添加安全验证Token 为什么选择wcf? 因为好像wcf和wpf就是哥俩,,, 为什么选择异步 ...
- Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天、消息模块
原文:Prism for WPF 搭建一个简单的模块化开发框架(五)添加聊天.消息模块 中秋节假期没事继续搞了搞 做了各聊天的模块,需要继续优化 第一步画页面 页面参考https://github.c ...
- Prism for WPF 搭建一个简单的模块化开发框架(二)
原文:Prism for WPF 搭建一个简单的模块化开发框架(二) 今天又有时间了,再改改,加了一些控件全局的样式 样式代码 <ResourceDictionary xmlns="h ...
- Prism for WPF 搭建一个简单的模块化开发框架(一)
原文:Prism for WPF 搭建一个简单的模块化开发框架(一) 最近闲来无事又想搞搞WPF..... 做个框架吧,可能又是半途而废....总是坚持不下来 不废话了, 先看一下工程结构 布局大概是 ...
- 用express搭建一个简单的博客系统
转自:https://blog.csdn.net/qq_29721837/article/details/62055603 Express 简介 Express 是一个简洁而灵活的 node.js W ...
- 从零开始搭建一个简单的基于webpack的vue开发环境
原文地址:https://segmentfault.com/a/1190000012789253?utm_source=tag-newest 从零开始搭建一个简单的基于webpack的react开发环 ...
- 用nodejs搭建一个简单的服务器
使用nodejs搭建一个简单的服务器 nodejs优点:性能高(读写文件) 数据操作能力强 官网:www.nodejs.org 验证是否安装成功:cmd命令行中输入node -v 如果显示版本号表示安 ...
随机推荐
- 漫谈 Clustering (4): Spectral Clustering
转:http://blog.pluskid.org/?p=287 如果说 K-means 和 GMM 这些聚类的方法是古代流行的算法的话,那么这次要讲的 Spectral Clustering 就可以 ...
- Topic model的变种及其应用[1]
转: http://www.blogbus.com/krischow-logs/65749376.html LDA 着实 带领着 Topic model 火了一把. 但是其实我们华人世界内,也不乏 ...
- QT信号和槽在哪个线程执行问题
时隔四个月后的第一篇,换了个公司可以登录的博客,记录一些学习内容吧 这是看到别人写的比较好的一篇,排版有点乱 QThread的使用方法 起源 昨天不小心看到Qt开发人员( Bradley T.Hugh ...
- 显示锁(ReentranLock)
1. Lock接口:定义了一组抽象的加锁操作,提供了一种无条件的.可轮询的.定时的以及可中断的锁获取操作,所有的加锁和解锁的方法都是显示的. 2. ReentrantLock锁:实现了Lock接口,并 ...
- Python解析配置文件模块:ConfigPhaser
算是前几周落下的博客补一篇.介绍一下python中如何解析配置文件.配置文件常用的几种格式:xml,json,还有ini.其中ini算是最简单的一种格式,因为小,解析的速度也要比xml和json快(并 ...
- Hibernate之openSession与getCurrentSession的区别
openSession 与 getCurrentSession的区别(1)openSession 每一次获得的是一个全新的session对象,而getCurrentSession获得的是与当前线程绑定 ...
- HTTP缓存机制--客户端缓存(转)
客户端缓存 客户端侧缓存一般指的是浏览器缓存,目的就是加速各种静态资源的访问,想想现在的大型网站,随便一个页面都是一两百个请求,每天 pv 都是亿级别,如果没有缓存,用户体验会急剧下降.同时服务器压力 ...
- php面试重要知识点,面试题
1.什么是引用变量,用什么符号定义引用变量? 概念:用不同的名称引用同一个变量的内容:用&符号定义. 例如: $a = range(0,100); $b = &$a; $b = ran ...
- [转载] iOS应用程序的生命周期
iOS应用程序的生命周期 2015-06-23 iOS大全 (点击上方蓝字,快速关注我们) iOS应用程序一般都是由自己编写的代码和系统框架(system frameworks)组成,系统框架提供一些 ...
- LeetCode28.实现strStr() JavaScript
实现 strStr() 函数. 给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始).如果不存在,则返 ...