日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【源码分享】WPF漂亮界面框架实现原理分析及源码分享

發布時間:2025/3/17 asp.net 13 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【源码分享】WPF漂亮界面框架实现原理分析及源码分享 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1 源碼下載

?

直接放出源碼地址,為了編譯源碼,需要下載安裝OSGi.NET插件框架安裝包:http://www.iopenworks.com/。

【1】框架安裝包:MuiTreeNavVsPackage.zip(使用方法見上一篇文章:分享一個漂亮WPF界面框架創作過程及其源碼)。

【2】框架源代碼:MuiTreeNavSource.zip? ? 注意:要正確編譯,必須安裝Nuget且連接網絡,必須提前安裝iOpenWorksSDK。

?

2 OSGi.NET插件應用架構概述

?

基于OSGi.NET插件框架的應用由以下三個部分構成:

(1)主程序:針對特定應用環境(WPF、Web、WinForm等應用環境),加載啟動插件,獲取插件入口,運行入口程序。

(2)插件:提供應用功能,實現對其它插件功能擴展并暴露功能擴展點。

(3)插件框架:與特定應用環境無關,實現插件的加載、啟動、停止、更新和卸載,實現插件功能組合與擴展。

?

3 漂亮界面框架原理概述

?

WPF漂亮界面框架最終展示效果如下圖所示。主界面中間區域的左邊是導航欄,右邊是顯示區域,點擊導航欄的導航節點后,在內容區域動態顯示其內容。此外,還提供了標題欄、狀態欄、系統菜單、系統設置等默認功能。

該界面,從功能上看,它由界面框架插件、演示插件、權限管理插件、插件中心插件以及通用功能插件構成,如下所示。

這些插件的功能組合關系如下所示,"應用 = 界面框架插件 + 功能插件(演示/權限管理/插件中心插件)擴展"。界面框架定義了系統主界面風格、可擴展的屬性導航欄、可擴展的內容區域等元素構成。

上述的權限管理插件除了提供角色管理/用戶管理功能,它還定義了一個登錄窗體。主程序exe文件在執行時,首先創建并啟動OSGi.NET插件框架,然后通過服務總線獲取權限管理插件注冊的登錄窗體,并顯示。此時,程序執行的控制權則完全交由插件。

在權限管理插件的登錄界面,登錄成功之后,它會顯示界面框架插件定義的MainWindow主界面。該主界面則開始來組合插件的功能。下面,我們來看看插件實現的細節。

?

4 漂亮界面框架實現

?

4.1 主程序

?

主程序主要實現:(1)創建啟動插件框架;(2)獲取入口,并進入入口程序。下面我們來看看這個WPF主程序的入口。

在App.xaml.cs中定義了一個函數StartBundleRuntime,如下所示。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 private?void?StartBundleRuntime() { ????…… ????// 創建BundleRuntime ????var?bundleRuntime =?new?BundleRuntime(); ????// 不啟動多版本支持 ????bundleRuntime.EnableAssemblyMultipleVersions =?false; ????// 監聽插件狀態變化,更新進度條 ????bundleRuntime.Framework.EventManager.AddBundleEventListener(BundleStateChangedHandler,?true); ????// 監聽框架狀態變化 ????bundleRuntime.Framework.EventManager.AddFrameworkEventListener(FrameworkStateChangedHandler); ????// 將Application實例添加到全局服務,與插件進行共享 ????bundleRuntime.AddService<Application>(this); ????// 啟動插件框架 ????bundleRuntime.Start(); ????// 移除事件監聽 ????bundleRuntime.Framework.EventManager.RemoveBundleEventListener(BundleStateChangedHandler,?true); ????bundleRuntime.Framework.EventManager.RemoveFrameworkEventListener(FrameworkStateChangedHandler); ????Startup += App_Startup; ????Exit += App_Exit; ????_bundleRuntime = bundleRuntime; }

在主程序中,它使用以下代碼來獲取入口,這個入口是一個LoginWindow。

1 2 3 4 5 6 7 8 9 10 11 private?void?App_Startup(object?sender, StartupEventArgs e) { ????…… ????// 獲取loginWindow實例,并顯示該窗口 ????var?loginWindow = bundleRuntime.GetFirstOrDefaultService<Window>(); ????loginWindow.Loaded += (sender2, e2) => ????{ ????????loginWindow.Activate(); ????}; ????loginWindow.Show(); }

?

4.2 主程序與插件的通訊

?

OSGi.NET插件框架提供了一個簡單的方式來實現主程序與插件間的通訊,即服務。

主程序可以通過插件框架BundleRuntime來注冊和獲取服務,插件可以通過插件激活器的上下文來注冊和獲取服務、或者使用BundleRuntime.Instance這個單例來注冊與獲取服務。也就是說,主程序的BundleRuntime、插件的上下文IBundleContext都是對應相同的服務總線。

服務在這里表述為:服務 = 接口/基類 + 實現類。比如ISayHelloService接口、SayHelloServiceBase基類、SayHelloService實現類。我們可以注冊服務為:

AddService<ISayHelloService>(new SayHelloService())

或者

AddService<SayHelloServiceBase>(new SayHelloService())

?

那么獲取服務的方式就是:

Get**Service<ISayHelloService>()

或者

Get**Service<SayHelloServiceBase>()

?

4.2.1主程序獲取插件注冊的服務

?

在該框架,主程序需要獲取權限管理插件注冊的登錄窗體,然后運行,接著將系統控制權轉交給插件。這時候,主程序通過以下代碼來獲取服務。

(1)創建啟動插件框架

var bundleRuntime = new BundleRuntime();bundleRuntime.Start();

(2)獲取服務

var loginWindow = bundleRuntime.GetFirstOrDefaultService<Window>();loginWindow.Show();

權限管理插件在Activator類中,通過以下代碼將LoginWindow注冊到服務總線。

public class Activator : IBundleActivator {public void Start(IBundleContext context){context.AddService<Window>(new LoginWindow());}public void Stop(IBundleContext context){} }

這里,需要注意的是:主程序只能等插件框架啟動起來后,才能夠獲取插件注冊的服務。

?

4.2.2插件獲取主程序注冊的服務

????

主程序可以為插件注冊全局的服務,這樣所有插件在啟動的時候,就可以直接來訪問。主程序注冊全局服務的代碼如下:

var bundleRuntime = new BundleRuntime();bundleRuntime.AddService<ISayHelloService>();bundleRuntime.Start();

注意:主程序在BundleRuntime.Start方法調用前注冊的服務,插件在啟動時即可獲取。

這時候,插件可以在激活器中直接獲取到該服務了。

public class Activator : IBundleActivator {public void Start(IBundleContext context){var sayHelloService = context.GetFirstOrDefaultService<ISayHelloService>();sayHelloService.Hell(“Lorry Chen”);}public void Stop(IBundleContext context){} }

?

4.2.3 服務接口

?

在4.2.1小節中,主程序和權限管理插件在處理服務時,使用Window這個類作為服務的契約。這個服務契約是在.NET Framework中直接定義的,因此主程序和插件都可以訪問到。如果我們新定義的服務SayHelloService(ISayHelloService接口、SayHelloService服務實現類),那么這時候主程序和插件都需要通過接口ISayHelloService來獲取服務,這時候建議將ISayHelloService接口定義到一個外部的程序集,主程序可以引用它,插件也可以依賴它。

?

4.3 權限管理的登錄窗體

?

基于4.2,我們發現通過服務可以實現主程序和插件之間的通訊。當主程序獲取到權限管理注冊的登錄窗體實例,便獲取該窗體并展現它,此后應用系統便交由插件來控制了。

在權限管理插件的登錄窗體,它由LoginUserControl.xaml來實現,在該頁面的后臺代碼的登錄處理函數中,一旦登錄成功,它將創建一個主窗體MainWindow,并且顯示該窗體,如下圖所示。

在這里,權限管理插件創建了主窗體MainWindow類,這個類實際上是由界面框架插件定義的主窗體。因此,該插件依賴了界面框架插件,并添加了對UIShell.WpfShellPlugin程序集的引用。如下所示。

通過上述的工作,登錄窗體在登錄成功之后,就可以顯示界面框架的主窗體了。

?

4.4 界面框架插件

?

應用系統由界面框架插件、服務插件和功能插件構成,它們的組合關系如下所示。

從界面功能上來講,系統由主界面框架、插件中心插件、權限管理插件、演示插件組成,在其背后還有一些非界面功能插件,比如數據庫訪問等。

界面框架插件提供了一個可擴展、可組合的界面功能展示。界面框架插件暴露了一個名為UIShell.NavigationService的擴展點,權限管理插件、插件中心插件、其它插件則定義了針對該擴展點的擴展。

界面框架對應的擴展格式如下所示。該格式由名為Node的XML節點組成,Node節點可以嵌套包含子節點。

1 2 3 4 5 6 7 8 9 10 11 12 <Extension?Point="UIShell.NavigationService"> ??<Node?Id="2E3614E0-388D-46E4-88A8-42E7CB3B421F" Name="權限管理" ????????Icon="/UIShell.RbacManagementPlugin;component/Assets/Permission.png" ????????Order="490"> ????<Node?Name="角色管理" Permission="RoleManagementPermission" ??????????Value="UIShell.RbacManagementPlugin.RolePermissionUserControl" ??????????Icon="/UIShell.RbacManagementPlugin;component/Assets/Role.png" Order="1" /> ????<Node?Name="用戶管理" Permission="UserManagementPermission" ??????????Value="UIShell.RbacManagementPlugin.UserPermissionUserControl" ??????????Icon="/UIShell.RbacManagementPlugin;component/Assets/User2.png" Order="2" /> ??</Node> </Extension>

當界面框架插件沒有加載任何擴展時,界面是空白的。左邊導航欄用于加載插件定義的導航菜單,右邊用于加載插件的顯示內容。

那么插件中心插件就是由對界面框架插件的擴展及如下功能構成,如下所示。

插件中心插件對界面框架插件的界面擴展是通過如下的Manifest.xml來定義的。

同理,權限管理插件也是對界面框架插件定義了擴展并實現了如下功能。

權限管理插件對界面框架的擴展定義在Manifest.xml中實現,如下所示。

課程管理這個示例插件也是如此。

?

4.4.1 導航服務

?

插件對界面框架的擴展的XML由導航服務來進行解析。通俗的講,該服務實現的是將以下XML節點變更NavigationNode對象。

<Extension Point="UIShell.NavigationService"><Node Id="2E3614E0-388D-46E4-88A8-42E7CB3B421F" Name="權限管理" Icon="/UIShell.RbacManagementPlugin;component/Assets/Permission.png" Order="490"><Node Name="角色管理" Permission="RoleManagementPermission" Value="UIShell.RbacManagementPlugin.RolePermissionUserControl" Icon="/UIShell.RbacManagementPlugin;component/Assets/Role.png" Order="1" /><Node Name="用戶管理" Permission="UserManagementPermission" Value="UIShell.RbacManagementPlugin.UserPermissionUserControl" Icon="/UIShell.RbacManagementPlugin;component/Assets/User2.png" Order="2" /></Node> </Extension>

NavigationNode對象如下圖所示,它包含子對象。該對象對應于XML節點。我們可以通過INavigationService來獲取這些對象集合。INavigationService會默認從名字為"UIShell.NavigationService"的擴展點來創建對象。如果我們使用了類似的導航擴展定義,但使用了不同的擴展點,可以使用INavigationServiceFactory來創建指定擴展點的導航服務。

導航服務還隱藏了針對擴展變更事件的處理。該服務暴露了NavigationChanged事件來通知導航節點變更。

?

4.4.2 界面框架擴展實現

?

界面框架首先需要實現一個空的布局,其內容區域為樹和空白顯示區域。樹使用TreeView,空白顯示區域的父控件是DockPanel。那么,該框架實現的核心就是將NavigationNode的集合轉換成TreeViewNode集合,當點擊TreeViewNode時,能夠將其對應的用戶控件加載。

界面框架的XAML如下所示。

<UserControl x:Class="UIShell.WpfShellPlugin.Pages.Layout"……><Grid Style="{StaticResource ContentRoot}"><DockPanel><DockPanel DockPanel.Dock="Bottom" Height="20" ……>……//Status Bars</DockPanel><Grid><Grid.ColumnDefinitions><ColumnDefinition Name="TreeViewColumn"></ColumnDefinition><ColumnDefinition Width="*"></ColumnDefinition></Grid.ColumnDefinitions><TreeView Grid.Column="0" Grid.Row="0" Name="NavigationTreeView" SelectedItemChanged="NavigationTreeView_SelectedItemChanged" /><GridSplitter DragCompleted="GridSplitter_DragCompleted" /><TextBlock Grid.Column="1" Grid.Row="0" Name="LoadingTextBlock" Text="加載中......" …… Visibility="Hidden"></TextBlock><Grid Grid.Column="1" Grid.Row="0" Name="LayoutDockPanel"></Grid></Grid></DockPanel><DockPanel Name="SideBarDockPanel" Background="{DynamicResource WindowBackground}" Width="300" HorizontalAlignment="Right" Visibility="Hidden"><Border BorderThickness="2" BorderBrush="{DynamicResource Accent}"><Grid><Grid.RowDefinitions><RowDefinition Height="45" /><RowDefinition Height="*" /></Grid.RowDefinitions><TextBlock Name="SideBarTitleTextBlock" Grid.Row="0" Margin="16, 16, 16, 0" Foreground="{DynamicResource Accent}" FontSize="20" /><DockPanel Grid.Row="1" Margin="16" Name="SideBarDockPanelContent"></DockPanel></Grid></Border></DockPanel></Grid> </UserControl>

從這些XAML片段,你可以看到,LayoutDockPanel這個名字的控件時用于放置動態加載的插件的控件,加載時機是在NavigationTreeView的SelectedItemChanged事件。另外,該界面框架還實現了SideBarDockPanel,用于支持從側面動態滑出一個側邊框。

下面我們看看界面框架針對擴展的處理。

接著我們看看ResetNavigation函數的實現。

其實現的核心就是InitializeNavigationTreeView。

該函數就是根據NavigationNode集合,遞歸創建TreeViewItem。下面我們來看看點擊樹形導航節點時,如何動態加載顯示插件的控件,其核心代碼如下。

從插件動態加載類型時,我們使用的是node.Bundle.LoadClass,即獲取擴展注冊的插件對象,調用該對象的LoadClass方法來加載用戶控件,然后將用戶控件顯示在LayoutDockPanel控件。

不過,當前界面框架還處理一些其它的功能:

(1)當前導航節點的側邊欄,即當切換菜單時,會自動打開/關閉與其關聯的側邊欄;

(2)緩存與關閉,即加載用戶控件后,會直接緩存,在切換時,會將前一個控件隱藏,接著顯示當前控件;只有關閉后,用戶控件才從父控件移除掉;

(3)關閉內容區域與導航節點選擇的同步,也就是說,關閉當前內容后,會默認顯示前一個頁面,此時,導航節點的選擇也必須同步切換;

(4)相關對象的關系存儲。

?

4.5 插件

?

下面我將從以下幾個方面來談一下開發插件過程中,需要處理的一些問題。

?

4.5.1 插件引用了第三方程序集

?

在主界面框架中,我們依靠第三方控件庫"ModernUI"來實現界面,并對"ModernUI"做深入的定制。在界面框架插件引用該控件時,首先,我們需要將該插件添加到Manifest.xml作為本地程序集,即界面框架插件在運行時需要與該程序集一起才能夠正常運行。

接著,可以直接從bin目錄來引用該程序集或者添加ModernUI源碼項目的程序集引用。

這時候,在界面框架插件中,就可以來直接使用ModernUI程序集的類型了。如下示例。

ModernDialog.ShowMessage("Hello, world!", "Hello", MessageButtongs.Ok);

或者

var dialog = new ModernDialog(){……};dialog.ShowDialog();

?

4.5.2 一個程序集如何讓所有插件都直接使用

?

在這個WPF應用程序,每一個插件在開發界面時大部分使用了MVVM架構,它依賴于MVVMLite這個庫。為了能夠讓插件直接使用,并且不需要將其添加到本地程序集的情況下來使用。我們可以在主程序里面直接添加對MVVMLite程序集的依賴,編譯后,每一個插件可以直接來引用主程序輸出目錄下的MVVMLite程序集。

你可以發現,MVVMLite程序集所在的位置。如果是Web應用的話,這些程序集所在目錄是bin目錄。這樣的程序集在OSGi.NET框架中成為全局程序集,默認開啟支持該功能。你可以通過設置BundleRuntime.EnableGlobalAssemblyFeature屬性開啟或者關閉該功能。

全局程序集有以下特點:(1)如果插件包含了另一個程序集,和該程序集名稱一樣,則會被替換掉;(2)全局程序集不支持多版本。

?

4.5.3 插件引用了另一個插件的程序集

?

在該界面框架中,所有UI插件都是基于ModernUI控件庫來實現。該控件庫在界面框架中包含。因此,我們的功能插件需要引用界面框架插件的ModernUI控件庫。

首先,在界面框架,需要將該程序集定義成共享。

接著,在功能插件中,需要添加對界面框架的依賴。

最后,插件就可以直接通過引用,來添加對該程序集的引用,并在代碼中來調用了。

?

4.5.4 插件間的通訊實現

?

插件間的通訊,有兩種方式,第一種是一個插件直接使用另一個插件的程序集的類,如4.5.3的方式;第二種是松耦合的方式,即使用服務。

比如,在演示插件,我們引用了配置服務。配置服務是在配置服務插件來創建的,該服務定義如下所示。

該插件通過Activator來注冊服務實例,如下所示。

using System; using System.Collections.Generic; using System.Text; using UIShell.OSGi;namespace UIShell.ConfigurationService {public class Activator : IBundleActivator{public void Start(IBundleContext context){context.AddService<IConfigurationService>(new ConfigurationService());}public void Stop(IBundleContext context){}} }

演示插件依賴于IConfigurationService接口所在的程序集,通過該接口來獲取服務,如下所示。

接著,在演示插件就可以通過以下方式來存儲或者獲取配置了。

BundleActivator.ConfigrationService.Set(BundleActivator.Bundle, "TreeViewColumnWidth", 80);

或者

var width = BundleActivator.ConfigurationService.Get(BundleActivator.Bundle, "TreeViewColumnWidth", 80);

?

4.5.5 如何從插件動態的加載類型

?

從插件加載類型的方式通過插件對象來實現。插件對象由OSGi.NET框架創建,可以通過插件激活器的IBundleContext.Bundle屬性獲取。

var bundle = Context.Bundle; // 或者var bundle = Context.GetBundleBySymbolicName("DemoPlugin"); var class = bundle.LoadClass("DemoPlugin.CourseManagementUserControl");

?

5 關于框架的藝術

?

框架的藝術并不在于技術本身,而是在于能夠幫助團隊更有效率的進行產品開發。為了提高產品開發效率,框架必須能夠提供:

(1)統一的開發模板:通過模板來規范團隊成員的編碼規則與規范功能模塊的架構,減少軟件開發的學習成本。比如,我們制作的演示插件模板,在這個模板基礎上做功能開發,是不需要你掌握多少關于框架本身的技術,而是專注于業務實現及通用功能的調用;此外,該模板規范了MVVM架構分層,統一了架構思想。

(2)一致的用戶體驗:通過框架為客戶定義了一致的界面風格,這使我們的軟件看上起更加的專業。

(3)良好的分工協作:通過框架,團隊成員可以專注于不同的功能模塊,進行有效率的并行協作。

?

6 總結

?

這個教程介紹了漂亮界面框架的架構、實現細節,通過這個教程,你已經能夠掌握使用OSGi.NET框架來開發一個漂亮界面框架了。


本文轉自道法自然博客園博客,原文鏈接:http://www.cnblogs.com/baihmpgy/p/osgi_muinavtree_fx.html,如需轉載請自行聯系原作者

總結

以上是生活随笔為你收集整理的【源码分享】WPF漂亮界面框架实现原理分析及源码分享的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 日韩免费在线视频 | 日韩欧美精品中文字幕 | 日韩av在线观看免费 | 色播视频在线 | 亚洲老妇色熟女老太 | 午夜免费看 | 亚洲人人夜夜澡人人爽 | 在线观看免费高清 | 欧美一区三区 | 日韩欧美精品免费 | 免费在线色视频 | 黄色在线观看免费 | 日韩乱码在线观看 | 好吊一区二区三区 | 国产在线国偷精品免费看 | 性av在线 | 香蕉视频免费网站 | 中文字幕高清视频 | 国产chinesehd天美传媒 | 一女双乳被两男吸视频 | 福利视频91| 91久久精品一区二区别 | 国产精品一二三四 | 亚洲国产精品一区二区三区 | 深夜视频在线看 | 青青色在线观看 | 欧日韩视频 | 欧美国产不卡 | 啪啪精品| 成人看片免费 | 自拍偷拍激情 | 麻豆免费电影 | 丁香花在线影院观看在线播放 | 丰满人妻一区二区三区免费 | 伊人网狼人 | 亚洲午夜av在线 | 国产超碰自拍 | h片在线看 | 亚洲精品一区二区18漫画 | 久久天堂网 | www视频在线免费观看 | 亚洲精品久久久久中文字幕二区 | 麻豆国产一区二区 | 免费黄色激情视频 | 亚洲s码欧洲m码国产av | heyzo朝桐光一区二区 | 亚洲欧美国产毛片在线 | 亚洲精品日日夜夜 | 日本成人精品 | 成人依人 | 高潮一区二区 | 91九色视频 | 亚欧美在线 | 日韩av一区二区三区四区 | 天天干免费视频 | 欧美高清视频一区二区三区 | 日本中文字幕高清 | 可以直接看av的网址 | 在线97 | 潘金莲一级淫片aaaaa | 久久久久久国产视频 | 免费人成在线观看 | 国产欧美成人 | 日剧大尺度床戏做爰 | 激情视频亚洲 | 亚洲爽爆 | 91老女人 | 国产ts变态重口人妖hd | av网址观看 | 精品人妻午夜一区二区三区四区 | 素人一区二区三区 | 天天看夜夜操 | 九九99精品视频 | 欧美久久久久久久久久久 | 99国产视频在线 | 铠甲勇士猎铠 | 麻豆视频网站 | 天天做天天爽 | 日韩欧美国产成人 | 99久久久成人国产精品 | 99久久久无码国产精品性色戒 | 久久久久久久伊人 | 在线国产一区二区 | 韩国19主播内部福利vip | 丰满少妇一区二区三区 | 日韩少妇视频 | 东方伊甸园av在线 | 四虎国产 | 四虎成人精品永久免费av | 在线视频日韩欧美 | 亚洲欧洲日韩av | 狠狠入 | 九九热在线视频免费观看 | 四虎永久地址 | 日韩夜夜高潮夜夜爽无码 | 亚洲黄a | 艳妇臀荡乳欲伦交换h漫 | 黄色三及 | 国产精品丝袜在线观看 |