在開發winform程序界面的時候,我們往往會使用一些較好看的圖表,以便能夠為我們的程序界面增色,良好的圖標設置可以讓界面看起來更加美觀舒服,而且也比較容易理解,圖標我們可以通過一些網站獲取各種場景的圖標資源,不過本篇隨筆主要介紹如何利用devexpress的內置圖標資源來實現界面圖標的設置。
1、設計時刻的圖標處理
豐富的圖標處理,在菜單、工具欄、樹列表等地方,以及按鈕等地方,都可以使用,而這些我們可以利用devexpress的內置圖標選擇來減輕我們尋找合適圖標的煩惱。
一些按鈕、工具欄等的圖標設置,一般是固定的,我們往往可以在設計時刻就指定它,這樣我們可以使用本地的圖標,也可以使用devexpress的內置圖標。而使用devexpress內置圖標資源的時候,我們可以調出devexpress的內置圖標選擇框的。
如下是按鈕添加圖標方式,操作非常簡單,在按鈕的右上角小圖標上單擊一下進入編輯界面,如下所示。
然后選擇image按鈕,進入圖標選擇界面,選擇內置的devexpress圖標庫即可,基本上,只要是devexpress的原生控件,那么就可以通過這種內置圖標的對話框進行圖標選擇,非常方便。
2、運行時刻的圖標處理
上面的操作是在設計時候,devexpress設計器給我們提供很多便利選擇內置圖標,而在界面運行時刻,想動態處理界面按鈕圖標,或者樹形菜單的圖標的時候,就沒有這個直接的接口來設置圖標了,而我們框架的菜單往往都是需用動態增加的,因此圖標的設置也是在運行時刻的。如下面的樹列表中,圖標就是動態指定的。
這些動態的樹形菜單,是在權限系統里面動態配置的,菜單的配置界面如下所示。
上面的選擇圖圖標就是我們需要動態設置的圖標,由于圖標資源我們是以圖片形式存儲在對應的記錄里面的,因此使用起來也是比較方便的,我們在配置的時候,獲取到對應的圖標資源并存儲起來即可。
除了上面可以參考從devexpress內置圖標資源獲取圖標的方式外
我們還可以選擇我們自己喜歡的圖標資源,也就是從系統圖標文件中選擇自己喜歡的,如下界面所示。
因此我考慮在運行時刻整合兩種不同選擇圖標的方式。
我們先來看看我整合后的圖表選擇界面,如下所示,包含了運行時刻提取devexpress內置圖標的功能和從系統文件中選擇圖標的功能。
3、運行時刻提取devexpress內置圖標的功能實現
首先我們參考設計時刻的界面展示
來設計一個界面來展示圖標信息
參考原版的界面,設計盡可能貼近即可,另外我們自己加入一個從系統選擇圖標資源的操作。
至于圖標選中后我們返回對應的image對象給調用者,則通過事件進行處理,以便選中后,即使更新顯示效果。
如下所示,我們定義一個委托和事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
/// <summary> /// devexpress圖標和系統圖標選擇窗體 /// </summary> public partial class frmimagegallery : baseform { /// <summary> /// 自定義一個委托處理圖標選擇 /// </summary> public delegate void iconselecthandlerdelegate(image image, string name); /// <summary> /// 圖標選擇的事件 /// </summary> public event iconselecthandlerdelegate oniconselected; private dximagegalleryloader loader = null ; public frmimagegallery() { initializecomponent(); initdictitem(); //初始化 } /// <summary> /// 處理圖標選擇的事件觸發 /// </summary> public virtual void processiconselected(image image, string name) { if (oniconselected != null ) { oniconselected(image, name); } } |
然后在內置圖標顯示中,如果觸發圖標的單擊,我們就觸發事件,以便讓調用者更新界面顯示,如下代碼所示。
1
2
3
4
5
6
7
8
|
foreach (galleryitem item in items[key]) { item.itemclick += (s, e) => { //選擇處理 processiconselected(item.imageoptions.image, item.description); }; } |
而對于從系統文件加載文件進行顯示圖標的,類似的觸發方式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
/// <summary> /// 從系統資源中加載圖標文件,然后觸發事件進行顯示 /// </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); } } |
這樣我們在菜單的選擇圖標的時候,就可以觸發事件進行獲取圖表并更新自身了。
1
2
3
4
5
6
7
8
9
|
private void btnselecticon_click( object sender, eventargs e) { frmimagegallery dlg = new frmimagegallery(); dlg.oniconselected += (image, name) => { this .txtembedicon.image = image; }; dlg.showdialog(); } |
完成了這些處理,我們再次將焦點放在如何提取并展示devexpress內置圖標的身上。
為了獲取圖表資源里面的分類及大小等信息,我們需要把圖標資源進行一個加載出來,然后讀取里面的類別和大小、集合等信息。先定義幾個變量來承載這些信息。
1
2
3
4
5
6
7
8
9
10
11
12
|
/// <summary> /// 圖標分類 /// </summary> public list< string > categories { get ; set ; } /// <summary> /// 圖標集合 /// </summary> public list< string > collection { get ; set ; } /// <summary> /// 圖標尺寸 /// </summary> public list< string > size { get ; set ; } |
我們知道,devexpress的圖標資源在程序集devexpress.utils.dximageassemblyutil.imageassembly里面,因此我們需要對它進行讀取,并依次對各個資源進行處理。
我們來看看具體的處理代碼,如下所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
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); } } } } } |
其中讀取資源的操作代碼是
1
|
getresourcereader(devexpress.utils.dximageassemblyutil.imageassembly) |
這個代碼它就是從資源里面進行獲取對應的圖表資源。
1
2
3
4
5
6
7
8
9
10
|
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])); } |
另外,我們根據圖表的文件名結構,我們通過正則表達式來讀取它的對應信息,然后把它的大小、類別、集合信息存儲起來。
1
2
3
4
5
|
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" ); |
圖表信息讀取了,我們需要解析它然后存儲起來,把圖標的image對象放在一個字典類別里面,方便按照組別進行展示。
1
2
3
4
5
6
7
8
9
|
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); } } |
有了這些資源,我們對它們進行搜索就顯得很方便了,我們如果需要根據文件名或者其他條件進行查詢集合的數據,提供一個通用的方法即可,如下代碼所示。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
/// <summary> /// 根據條件獲取集合 /// </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) { //使用正則表達式獲取圖標文件名中的集合、類別、大小等信息 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 (! string .isnullorempty(filename)) { if (key.contains(filename)) { list.add(imagecollection[key]); } dict[ "查詢結果" ] = 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 進行搜索的了,不用再次讀取程序集并依次分析它,速度提供不少的。
由于圖表資源的處理是比較耗時的,我們把整個圖標加載的類作為一個靜態的對象緩存起來,這樣下次使用直接從緩存里面拿,對應的資源也不用重新加載,更好的提高我們重用的效果了,體驗更好了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/// <summary> /// 圖標庫加載處理 /// </summary> public class dximagegalleryloader { /// <summary> /// 圖標字典類別集合 /// </summary> public dictionary< string , galleryitem> imagecollection { get ; set ; } /// <summary> /// 圖標分類 /// </summary> public list< string > categories { get ; set ; } /// <summary> /// 圖標集合 /// </summary> public list< string > collection { get ; set ; } /// <summary> /// 圖標尺寸 /// </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; } } |
以上代碼通過
1
|
public static dximagegalleryloader default |
定義了一個靜態的實例屬性,這樣這個 dximagegalleryloader 實例只會在程序第一次使用的時候構建并加載圖片資源,后續都是從緩存里面讀取,提高響應速度的同時,也會記住上次的選擇界面內容。
以上就是整個功能的處理思路,以及一步步的優化處理,以便實現功能展示的同時,也提高響應速度,最終界面就是我們開始的時候介紹的那樣。
單擊或者選中系統圖標后, 需要設置的按鈕或者界面,就會及時更新圖標展示,體驗效果還是非常不錯的。
由于這個界面功能的通用性,我把它作為系統界面基礎模塊,放到了我的框架baseuidx里面,各個系統模塊都可以調用了。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.cnblogs.com/wuhuacong/p/10095661.html