轉(zhuǎn)帖|使用教程|編輯:龔雪|2023-11-03 11:28:35.243|閱讀 161 次
概述:本文將為大家介紹在WinForm開發(fā)框架中如何使用DevExpress的內(nèi)置圖標(biāo)資源,歡迎下載相關(guān)組件體驗!
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
相關(guān)鏈接:
在開發(fā)Winform程序界面的時候,我們往往會使用一些較好看的圖表,以便能夠為程序界面增色,良好的圖標(biāo)設(shè)置可以讓界面看起來更加美觀舒服,而且也比較容易理解。圖標(biāo)我們可以通過一些網(wǎng)站獲取各種場景的資源,不過本文主要介紹如何利用DevExpress 的內(nèi)置圖標(biāo)資源來實現(xiàn)界面圖標(biāo)的設(shè)置。
PS:給大家推薦一個C#開發(fā)可以用到的界面組件——DevExpress WinForms,它能完美構(gòu)建流暢、美觀且易于使用的應(yīng)用程序,無論是Office風(fēng)格的界面,還是分析處理大批量的業(yè)務(wù)數(shù)據(jù),它都能輕松勝任!
DevExpress技術(shù)交流群9:909157416 歡迎一起進(jìn)群討論
豐富的圖標(biāo)處理,在菜單、工具欄、樹列表等地方,以及按鈕等地方,都可以使用,而這些我們可以利用DevExpress的內(nèi)置圖標(biāo)選擇來減輕我們尋找合適圖標(biāo)的煩惱。
一些按鈕、工具欄等的圖標(biāo)設(shè)置一般是固定的,往往可以在設(shè)計時刻就指定它,這樣我們可以使用本地的圖標(biāo),也可以使用DevExpresss的內(nèi)置圖標(biāo)。而使用DevExpress內(nèi)置圖標(biāo)資源的時候,可以調(diào)出DevExpress的內(nèi)置圖標(biāo)選擇框的。
如下是按鈕添加圖標(biāo)方式,操作非常簡單,在按鈕的右上角小圖標(biāo)上單擊一下進(jìn)入編輯界面,如下所示。
然后選擇Image按鈕,進(jìn)入圖標(biāo)選擇界面,選擇內(nèi)置的DevExpress圖標(biāo)庫即可,基本上,只要是DevExpress的原生控件,那么就可以通過這種內(nèi)置圖標(biāo)的對話框進(jìn)行圖標(biāo)選擇,非常方便。
上面的操作是在設(shè)計時,DevExpress設(shè)計器給我們提供很多便利選擇內(nèi)置圖標(biāo),而在界面運行時,想動態(tài)處理界面按鈕圖標(biāo),或者樹形菜單的圖標(biāo)的時候,就沒有這個直接的接口來設(shè)置圖標(biāo)了,而我們框架的菜單往往都是需用動態(tài)增加的,因此圖標(biāo)的設(shè)置也是在運行時的。如下面的樹列表中,圖標(biāo)就是動態(tài)指定的。
這些動態(tài)的樹形菜單,是在權(quán)限系統(tǒng)里面動態(tài)配置的,菜單的配置界面如下所示。
上面的選擇圖圖標(biāo)就是我們需要動態(tài)設(shè)置的圖標(biāo),由于圖標(biāo)資源是以圖片形式存儲在對應(yīng)的記錄里面的,因此使用起來也是比較方便的。我們在配置的時候,獲取到對應(yīng)的圖標(biāo)資源并存儲起來即可。
除了上面可以參考從DevExpress內(nèi)置圖標(biāo)資源獲取圖標(biāo)的方式外。
我們還可以選擇自己喜歡的圖標(biāo)資源,也就是從系統(tǒng)圖標(biāo)文件中選擇自己喜歡的,如下界面所示。
因此考慮在運行時整合兩種不同選擇圖標(biāo)的方式。
我們先來看看整合后的圖表選擇界面,如下所示,包含了運行時刻提取DevExpress內(nèi)置圖標(biāo)的功能和從系統(tǒng)文件中選擇圖標(biāo)的功能。
首先我們參考設(shè)計時的界面展示:
來設(shè)計一個界面來展示圖標(biāo)信息:
參考原版的界面,設(shè)計盡可能貼近即可,另外我們自己加入一個從系統(tǒng)選擇圖標(biāo)資源的操作。
至于圖標(biāo)選中后我們返回對應(yīng)的Image對象給調(diào)用者,則通過事件進(jìn)行處理,以便選中后,即使更新顯示效果。
如下所示,我們定義一個委托和事件。
/// <summary> /// DevExpress圖標(biāo)和系統(tǒng)圖標(biāo)選擇窗體 /// </summary> public partial class FrmImageGallery : BaseForm { /// <summary> /// 自定義一個委托處理圖標(biāo)選擇 /// </summary> public delegate void IconSelectHandlerDelegate(Image image, string name); /// <summary> /// 圖標(biāo)選擇的事件 /// </summary> public event IconSelectHandlerDelegate OnIconSelected; private DXImageGalleryLoader loader = null; public FrmImageGallery() { InitializeComponent(); InitDictItem();//初始化 } /// <summary> /// 處理圖標(biāo)選擇的事件觸發(fā) /// </summary> public virtual void ProcessIconSelected(Image image, string name) { if (OnIconSelected != null) { OnIconSelected(image, name); } }
然后在內(nèi)置圖標(biāo)顯示中,如果觸發(fā)圖標(biāo)的單擊,我們就觸發(fā)事件,以便讓調(diào)用者更新界面顯示,如下代碼所示。
foreach (GalleryItem item in items[key]) { item.ItemClick += (s, e) => { //選擇處理 ProcessIconSelected(item.ImageOptions.Image, item.Description); }; }
而對于從系統(tǒng)文件加載文件進(jìn)行顯示圖標(biāo)的,類似的觸發(fā)方式。
/// <summary> /// 從系統(tǒng)資源中加載圖標(biāo)文件,然后觸發(fā)事件進(jìn)行顯示 /// </summary> private void txtFilePath_Properties_ButtonClick(object sender, ButtonPressedEventArgs e) { string file = GetIconPath(); if (!string.IsNullOrEmpty(file)) { this.txtFilePath.Text = file;//記錄文件名 this.txtEmbedIcon.Image = LoadIcon(file);//顯示圖片 this.txtEmbedIcon.Size = new System.Drawing.Size(64, 64); //返回處理 ProcessIconSelected(this.txtEmbedIcon.Image, file); } }
這樣我們在菜單的選擇圖標(biāo)的時候,就可以觸發(fā)事件進(jìn)行獲取圖表并更新自身了。
private void btnSelectIcon_Click(object sender, EventArgs e) { FrmImageGallery dlg = new FrmImageGallery(); dlg.OnIconSelected += (image, name) => { this.txtEmbedIcon.Image = image; }; dlg.ShowDialog(); }
完成了這些處理,我們再次將焦點放在如何提取并展示DevExpress內(nèi)置圖標(biāo)的身上。
為了獲取圖表資源里面的分類及大小等信息,我們需要把圖標(biāo)資源進(jìn)行一個加載出來,然后讀取里面的類別和大小、集合等信息。先定義幾個變量來承載這些信息。
/// <summary> /// 圖標(biāo)分類 /// </summary> public List<string> Categories { get; set; } /// <summary> /// 圖標(biāo)集合 /// </summary> public List<string> Collection { get; set; } /// <summary> /// 圖標(biāo)尺寸 /// </summary> public List<string> Size { get; set; }
DevExpress的圖標(biāo)資源在程序集DevExpress.Utils.DxImageAssemblyUtil.ImageAssembly里面,因此我們需要對它進(jìn)行讀取,并依次對各個資源進(jìn)行處理。
來看看具體的處理代碼,如下所示。
using (System.Resources.ResourceReader reader = GetResourceReader(DevExpress.Utils.DxImageAssemblyUtil.ImageAssembly)) { System.Collections.IDictionaryEnumerator dict = reader.GetEnumerator(); while (dict.MoveNext()) { string key = (string)dict.Key as string; if (!DevExpress.Utils.DxImageAssemblyUtil.ImageProvider.IsBrowsable(key)) continue; if (key.EndsWith(".png", StringComparison.Ordinal)) { string reg = @"(?<collection>\S*?)/(?<category>\S*?)/(?<name>\S*)"; var collectionItem = CRegex.GetText(key, reg, "collection"); var categoryItem = CRegex.GetText(key, reg, "category"); string sizeReg = @"_(?<size>\S*)\."; var sizeItem = CRegex.GetText(key, sizeReg, "size"); if (!this.Collection.Contains(collectionItem)) { this.Collection.Add(collectionItem); } if (!this.Categories.Contains(categoryItem)) { this.Categories.Add(categoryItem); } if (!this.Size.Contains(sizeItem)) { this.Size.Add(sizeItem); } Image image = GetImageFromStream((System.IO.Stream)dict.Value); if (image != null) { var item = new DevExpress.XtraBars.Ribbon.GalleryItem(image, key, key); if (!ImageCollection.ContainsKey(key)) { ImageCollection.Add(key, item); } } } } }
其中讀取資源的操作代碼是:
GetResourceReader(DevExpress.Utils.DxImageAssemblyUtil.ImageAssembly)
這個代碼它就是從資源里面進(jìn)行獲取對應(yīng)的圖表資源。
private System.Resources.ResourceReader GetResourceReader(System.Reflection.Assembly imagesAssembly) { var resources = imagesAssembly.GetManifestResourceNames(); var imageResources = Array.FindAll(resources, resourceName => resourceName.EndsWith(".resources")); if (imageResources.Length != 1) { throw new Exception("讀取異常"); } return new System.Resources.ResourceReader(imagesAssembly.GetManifestResourceStream(imageResources[0])); }
另外根據(jù)圖表的文件名結(jié)構(gòu),我們通過正則表達(dá)式來讀取它的對應(yīng)信息,然后把它的大小、類別、集合信息存儲起來。
string reg = @"(?<collection>\S*?)/(?<category>\S*?)/(?<name>\S*)"; var collectionItem = CRegex.GetText(key, reg, "collection"); var categoryItem = CRegex.GetText(key, reg, "category"); string sizeReg = @"_(?<size>\S*)\."; var sizeItem = CRegex.GetText(key, sizeReg, "size");
圖表信息讀取了,我們需要解析它然后存儲起來,把圖標(biāo)的Image對象放在一個字典類別里面,方便按照組別進(jìn)行展示。
Image image = GetImageFromStream((System.IO.Stream)dict.Value); if (image != null) { var item = new DevExpress.XtraBars.Ribbon.GalleryItem(image, key, key); if (!ImageCollection.ContainsKey(key)) { ImageCollection.Add(key, item); } }
有了這些資源,我們對它們進(jìn)行搜索就顯得很方便了,如果需要根據(jù)文件名或者其他條件進(jìn)行查詢集合的數(shù)據(jù),提供一個通用的方法即可,如下代碼所示。
/// <summary> /// 根據(jù)條件獲取集合 /// </summary> /// <returns></returns> public Dictionary<string, GalleryItemCollection> Search(List<string> collection, List<string> categories, List<string> size, string fileName = "") { Dictionary<string, GalleryItemCollection> dict = new Dictionary<string, GalleryItemCollection>(); GalleryItemCollection list = new GalleryItemCollection(); foreach (var key in ImageCollection.Keys) { //使用正則表達(dá)式獲取圖標(biāo)文件名中的集合、類別、大小等信息 string reg = @"(?<collection>\S*?)/(?<category>\S*?)/(?<name>\S*)"; var collectionItem = CRegex.GetText(key, reg, "collection"); var categoryItem = CRegex.GetText(key, reg, "category"); string sizeReg = @"_(?<size>\S*)\."; var sizeItem = CRegex.GetText(key, sizeReg, "size"); //如果是查詢處理,把記錄放到查詢結(jié)果里面 if (!string.IsNullOrEmpty(fileName)) { if(key.Contains(fileName)) { list.Add(ImageCollection[key]); } dict["查詢結(jié)果"] = list; } else { //如果是集合和列表中包含的,把它們按類別添加到字典里面 if (collection.Contains(collectionItem) && categories.Contains(categoryItem) && size.Contains(sizeItem)) { if (!dict.ContainsKey(categoryItem)) { GalleryItemCollection cateList = new GalleryItemCollection(); cateList.Add(ImageCollection[key]); dict[categoryItem] = cateList; } else { GalleryItemCollection cateList = dict[categoryItem]; cateList.Add(ImageCollection[key]); } } } } return dict; }
這次搜索就直接基于已有的集合ImageCollection 進(jìn)行搜索的了,不用再次讀取程序集并依次分析它,速度提供不少的。
由于圖表資源的處理是比較耗時的,我們把整個圖標(biāo)加載的類作為一個靜態(tài)的對象緩存起來,這樣下次使用直接從緩存里面拿,對應(yīng)的資源也不用重新加載,更好的提高重用的效果了,體驗更好了。
/// <summary> /// 圖標(biāo)庫加載處理 /// </summary> public class DXImageGalleryLoader { /// <summary> /// 圖標(biāo)字典類別集合 /// </summary> public Dictionary<string, GalleryItem> ImageCollection { get; set; } /// <summary> /// 圖標(biāo)分類 /// </summary> public List<string> Categories { get; set; } /// <summary> /// 圖標(biāo)集合 /// </summary> public List<string> Collection { get; set; } /// <summary> /// 圖標(biāo)尺寸 /// </summary> public List<string> Size { get; set; } /// <summary> /// 使用緩存處理,獲得對象實例 /// </summary> public static DXImageGalleryLoader Default { get { System.Reflection.MethodBase method = System.Reflection.MethodBase.GetCurrentMethod(); string keyName = string.Format("{0}-{1}", method.DeclaringType.FullName, method.Name); var result = MemoryCacheHelper.GetCacheItem<DXImageGalleryLoader>(keyName, delegate () { return new DXImageGalleryLoader().LoadData(); }, new TimeSpan(0, 30, 0));//30分鐘過期 return result; } }
以上代碼通過:
public static DXImageGalleryLoader Default
定義了一個靜態(tài)的實例屬性,這樣這個 DXImageGalleryLoader 實例只會在程序第一次使用的時候構(gòu)建并加載圖片資源,后續(xù)都是從緩存里面讀取,提高響應(yīng)速度的同時,也會記住上次的選擇界面內(nèi)容。
以上就是整個功能的處理思路,以及一步步的優(yōu)化處理,以便實現(xiàn)功能展示的同時,也提高響應(yīng)速度,最終界面就是我們開始的時候介紹的那樣。
單擊或者選中系統(tǒng)圖標(biāo)后, 需要設(shè)置的按鈕或者界面,就會及時更新圖標(biāo)展示,體驗效果還是非常不錯的。
由于這個界面功能的通用性,我把它作為系統(tǒng)界面基礎(chǔ)模塊,放到了我的框架BaseUIDx里面,各個系統(tǒng)模塊都可以調(diào)用了。
本文轉(zhuǎn)載自:
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自: