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="&#xe643;" -->
                                    <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="&#xe625;" 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="&#xe624;" />
                            </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?

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

猜你喜欢

转载自blog.csdn.net/shishuwei111/article/details/81773372