前些時間研究了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功能圖:
現在我做了個實例,整合模仿Office 2010的Ribbon效果:
(1)Blue:
(2)Silver
(3)Black
我把框架的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); }
項目解決方案圖:
現在只稍微提一下,後續有時間再把更詳細的設計方法說明。
源碼: http://files.cnblogs.com/aganqin/TLAgent.Ribbon.App.DemoDock4.rar