Ribbon整合Avalondock 2.0实现多文档界面设计(一)

Ribbon整合Avalondock 2.0实现多文档界面设计(一)前些时间研究了WPF的一些框架,感觉基于Prism框架的MVVM模式对系统的UI与逻辑分离很好,所以就按照之前Winform的框架设计,用WPF做了一套,感觉比Winform要强很多。MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点1.低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,…

大家好,又见面了,我是你们的朋友全栈君。

前些时间研究了WPF的一些框架,感觉基于Prism框架的MVVM模式对系统的UI与逻辑分离很好,所以就按照之前Winform的框架设计,用WPF做了一套,感觉比Winform要强很多。

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点

1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的”View”上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。

2. 可重用性。你可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。

3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。

4. 可测试。界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

MVVM功能图:

1

现在我做了个实例,整合模仿Office 2010的Ribbon效果:

(1)Blue:

systemUI

(2)Silver

silver2

(3)Black

black

black2

我把框架的View设计和框架设计简单介绍一下。

View的XAML源码:

<!--<Window x:Class="TLAgent.Ribbon.App.Demo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        
    </Grid>
</Window>-->
<Fluent:RibbonWindow x:Class="TLAgent.Ribbon.App.Demo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Fluent="clr-namespace:Fluent;assembly=Fluent"
    xmlns:ad="http://schemas.xceed.com/wpf/xaml/avalondock"
    xmlns:vm="clr-namespace:TLAgent.Ribbon.App.Demo"
    Title="TLAgent.Ribbon.Application" Width="500" Height="250" Background="#FFEBEDF0" x:Name="window" WindowState="Maximized" WindowStartupLocation="CenterScreen" Icon="/TLAgent.Ribbon.App.Demo;component/Images/usergroup.ico">
    
    <Grid x:Name="layoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Fluent:Ribbon Grid.Row="0">
            <!--Add QuickAccess-->
            <Fluent:Ribbon.QuickAccessItems>
                <Fluent:QuickAccessMenuItem Target="{Binding ElementName=ButtonGreen}"/>
                <Fluent:QuickAccessMenuItem Target="{Binding ElementName=ButtonGray}"/>
            </Fluent:Ribbon.QuickAccessItems>
            <!--Add Tabs-->
            <Fluent:RibbonTabItem Header="Home" ReduceOrder="(P),(P),(P),(P),(P)">
                <Fluent:RibbonGroupBox Header="Add / Remove">
                    <Fluent:Button Header="Add" Command="{Binding AddFunctionCommand}" Icon="Images\Green.png" LargeIcon="Images\GreenLarge.png" Name="ButtonGreen" />
                    <Fluent:Button Header="Remove" Command="{Binding OpenCommand}" Icon="Images\Gray.png" LargeIcon="Images\GrayLarge.png" Name="ButtonGray" />
                </Fluent:RibbonGroupBox>
                <Fluent:RibbonGroupBox Header="Modify">
                    <Fluent:Button Header="Add" Command="{Binding AddFunctionCommand}" Icon="Images\Green.png" LargeIcon="Images\GreenLarge.png" Name="ButtonGreen1" />
                    <Fluent:Button Header="Remove" Command="{Binding OpenCommand}" Icon="Images\Gray.png" LargeIcon="Images\GrayLarge.png" Name="ButtonGray1" />
                </Fluent:RibbonGroupBox>
            </Fluent:RibbonTabItem>
            
            <Fluent:RibbonTabItem Header="用户管理" ReduceOrder="(P),(P),(P),(P),(P)">
                <Fluent:RibbonGroupBox Header="User Management">
                    <Fluent:Button Header="New User"  Icon="Images\Pink.png" LargeIcon="Images\PinkLarge.png" Name="ButtonAddUser" />
                    <Fluent:Button Header="Modify User" Icon="Images\Orange.png" LargeIcon="Images\OrangeLarge.png" Name="ButtonModiryUser" />
                </Fluent:RibbonGroupBox>
            </Fluent:RibbonTabItem>
            <!--Backstage Items-->
            <Fluent:Ribbon.Menu>
                <Fluent:Backstage Background="Gray">
                    <Fluent:BackstageTabControl>
                        <Fluent:Button Header="退出系统" Command="{Binding ExitSystemCommand}" Icon="Images\close.png"/>
                    </Fluent:BackstageTabControl>
                </Fluent:Backstage>
            </Fluent:Ribbon.Menu>

        </Fluent:Ribbon>

        <ad:DockingManager x:Name="dockManager" Grid.Row="1">
            <ad:DockingManager.Theme>
                <ad:ExpressionBlueTheme/>
            </ad:DockingManager.Theme>
            <ad:LayoutRoot>
                <ad:LayoutPanel Orientation="Vertical">
                    <ad:LayoutDocumentPane/>
                    <ad:LayoutAnchorablePane Name="ToolsPane" DockHeight="150">
                    </ad:LayoutAnchorablePane>
                </ad:LayoutPanel>
            </ad:LayoutRoot>
        </ad:DockingManager>
        <StatusBar VerticalAlignment="Bottom" Height="23" Grid.Row="2" >
            <StatusBarItem VerticalContentAlignment="Center">
                <TextBlock x:Name="TxtMessage" Foreground="{Binding ForeColor}" FontWeight="Bold" Text="{Binding ExecuteMessage}"/>
            </StatusBarItem>
        </StatusBar>
    </Grid>
    <!--<Window.DataContext>
        <vm:WorkspaceViewModel />
    </Window.DataContext>-->
</Fluent:RibbonWindow>

ViewModel源码:

/************************************************************************

   AvalonDock

   Copyright (C) 2007-2013 Xceed Software Inc.

   This program is provided to you under the terms of the New BSD
   License (BSD) as published at http://avalondock.codeplex.com/license 

   For more features, controls, and fast professional support,
   pick up AvalonDock in Extended WPF Toolkit Plus at http://xceed.com/wpf_toolkit

   Stay informed: follow @datagrid on Twitter or Like facebook.com/datagrids

  **********************************************************************/

using System;
using System.ComponentModel;
using System.Linq;
using System.Windows.Media;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Prism.ViewModel;
using System.Windows;
using TLAgent.WPF.Theme;
using Xceed.Wpf.AvalonDock;
using Xceed.Wpf.AvalonDock.Layout;

namespace TLAgent.Ribbon.App.Demo
{
    class WorkspaceViewModel : NotificationObject
    {
        public DelegateCommand AddFunctionCommand { get; set; }

        public DelegateCommand ExitSystemCommand { get; set; }

        public DelegateCommand OpenCommand { get; set; }

        private  DockingManager _dockingManager; 

        public WorkspaceViewModel()
        {
           _dockingManager = MainWindow.DockingManager;

            AddFunctionCommand = new DelegateCommand(this.OnNew);

            ExitSystemCommand = new DelegateCommand(this.OnExit);

            OpenCommand = new DelegateCommand(this.OnOpen);

        }

        private void OnOpen()
        {
            //string frameworkPath = string.Format("/Fluent;component/Themes/Office2010/{0}.xaml", ThemeStyle.Silver);//主框架的样式文件
            //Application.Current.Resources.MergedDictionaries.Clear();
            //设置界面控件的样式
            //设置界面框架的样式
            //Application.Current.Resources.MergedDictionaries.Add((ResourceDictionary)(Application.LoadComponent(new Uri(frameworkPath, UriKind.RelativeOrAbsolute))));
        }

        private string _executeMessage;

        public string ExecuteMessage
        {
            get { return _executeMessage; }
            set { _executeMessage = value;
            this.RaisePropertyChanged("ExecuteMessage");
            }
        }
        
        private Brush _foreColor;

        public Brush ForeColor
        {
            get { return _foreColor; }
            set
            {
                _foreColor = value;
                this.RaisePropertyChanged("ForeColor");
            }
        }
        

        private void OnNew()
        {
            string functionName = "项目管理";
            CreateSystemTab(functionName);
            ForeColor = new SolidColorBrush(Colors.White);

            var leftAnchorGroup = _dockingManager.Layout.LeftSide.Children.FirstOrDefault();
            if (leftAnchorGroup == null)
            {
                leftAnchorGroup = new LayoutAnchorGroup();
                _dockingManager.Layout.LeftSide.Children.Add(leftAnchorGroup);
            }
            
            leftAnchorGroup.Children.Add(new LayoutAnchorable() { Title = "New Anchorable" });
            ExecuteMessage = "成功新建,Tabs:" + functionName;
        }

        private void CreateSystemTab(string tabName)
        {
            var firstDocumentPane =_dockingManager.Layout.Descendents().OfType<LayoutDocumentPane>().FirstOrDefault();
            if (firstDocumentPane != null)
            {

                LayoutDocument doc2 = new LayoutDocument();
                AddUserWindow control1 = new AddUserWindow();
                doc2.Title = tabName;
                doc2.Content = control1;
                doc2.IsActive = true;
                firstDocumentPane.Children.Add(doc2);

            }
        }

        private void OnExit()
        {
            MessageBoxResult result = MessageBox.Show("确定要退出系统吗?", "确认消息", MessageBoxButton.OKCancel, MessageBoxImage.Question);
            if (result == MessageBoxResult.OK)
            {
                Application.Current.Shutdown();
                var serializer = new Xceed.Wpf.AvalonDock.Layout.Serialization.XmlLayoutSerializer(_dockingManager);
                serializer.Serialize(@".\AvalonDock.config");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

更换主题:提供统一的接口就可以实现整合框架和控件主题更换。

/// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : RibbonWindow
    {
        public static DockingManager DockingManager;

        public MainWindow()
        {
            InitializeComponent();
            DockingManager = dockManager;
            ThemeManager.ChangeTheme(dockManager, ThemeStyle.Black);//更换主题接口
            this.DataContext = new WorkspaceViewModel();
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
            this.Unloaded += new RoutedEventHandler(MainWindow_Unloaded); 
        }

项目解决方案图:

project

现在只稍微提一下,后续有时间再把更详细的设计方法说明。

转载于:https://www.cnblogs.com/happyyftk/p/6904325.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/162130.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月20日 下午2:00
下一篇 2022年7月20日 下午2:00


相关推荐

  • Fork/Join框架阅读笔记[通俗易懂]

    Fork/Join框架阅读笔记[通俗易懂]什么是Fork/Join框架Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干 个小任务,最终汇总每个小任务结果后得到大任务结果的框架。 我们再通过Fork和Join这两个单词来理解一下Fork/Join框架。Fork就是把一个大任务切分 为若干子任务并行的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结 果。比如计算1+2+…+10000,可以分割成10个子任务,每个子任务分别对1000个数进行求和, 最终汇总这10个子任务的结果。Fork/

    2022年8月9日
    15
  • css五大布局方式详解

    css五大布局方式详解css 布局方式 table 布局 float 布局 flex 布局响应式布局 Grid 布局 table 布局 table 布局在如今已经很少使用 原因是 table 布局比其它 html 标记占更多的字节 会阻挡浏览器渲染引擎的渲染顺序 会影响其内部的某些布局属性的生效 使用 table 布局有两种方式 table 标签 display table 标签与 js 的对应 table display table tr display table row thead displ

    2026年3月17日
    2
  • 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)

    张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么需要标定,标定需要的输入和输出分别是哪些?相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。相机标定的输入:标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下…

    2022年5月28日
    34
  • INS-20802 Oracle Cluster Verification Utility failed解释说明[通俗易懂]

    INS-20802 Oracle Cluster Verification Utility failed解释说明

    2022年4月2日
    175
  • Cocos2dx 3.0开发环境的搭建–Eclipse建立在Android工程

    Cocos2dx 3.0开发环境的搭建–Eclipse建立在Android工程

    2022年1月15日
    37
  • 最全的PHP后台管理系统源码「建议收藏」

    最全的PHP后台管理系统源码「建议收藏」一款PHP语言基于ThinkPhp6.x+Layui+MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开发、提升开发效率的初衷,框架自研了一套个性化的组件,实现了可插拔的组件式开发方式:单图上传、多图上传、下拉选择、开关按钮、单选按钮、多选按钮、图片裁剪等等一系列个性化、轻量级的组件,是一款真正意义上实现组件化开发的敏捷开发框架,框架已集成了完整的RBAC权限架构和常规基础模块,同时支持多

    2025年12月10日
    4

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号