WinForm应用界面开发实战 - 如何使用DevExpress内置图标资源?

发布时间:2026/8/1 19:31:44

WinForm应用界面开发实战 - 如何使用DevExpress内置图标资源? 在开发Winform程序界面的时候我们往往会使用一些较好看的图表以便能够为程序界面增色良好的图标设置可以让界面看起来更加美观舒服而且也比较容易理解。图标我们可以通过一些网站获取各种场景的资源不过本文主要介绍如何利用DevExpress的内置图标资源来实现界面图标的设置。PS给大家推荐一个C#开发可以用到的界面组件——DevExpress WinForms它能完美构建流畅、美观且易于使用的应用程序无论是Office风格的界面还是分析处理大批量的业务数据它都能轻松胜任DevExpress新旧版本帮助文档下载可进QQ qun获取169725316一、设计时的图标处理丰富的图标处理在菜单、工具栏、树列表等地方以及按钮等地方都可以使用而这些我们可以利用DevExpress的内置图标选择来减轻我们寻找合适图标的烦恼。一些按钮、工具栏等的图标设置一般是固定的往往可以在设计时刻就指定它这样我们可以使用本地的图标也可以使用DevExpresss的内置图标。而使用DevExpress内置图标资源的时候可以调出DevExpress的内置图标选择框的。如下是按钮添加图标方式操作非常简单在按钮的右上角小图标上单击一下进入编辑界面如下所示。然后选择Image按钮进入图标选择界面选择内置的DevExpress图标库即可基本上只要是DevExpress的原生控件那么就可以通过这种内置图标的对话框进行图标选择非常方便。二、运行时的图标处理上面的操作是在设计时DevExpress设计器给我们提供很多便利选择内置图标而在界面运行时想动态处理界面按钮图标或者树形菜单的图标的时候就没有这个直接的接口来设置图标了而我们框架的菜单往往都是需用动态增加的因此图标的设置也是在运行时的。如下面的树列表中图标就是动态指定的。这些动态的树形菜单是在权限系统里面动态配置的菜单的配置界面如下所示。上面的选择图图标就是我们需要动态设置的图标由于图标资源是以图片形式存储在对应的记录里面的因此使用起来也是比较方便的。我们在配置的时候获取到对应的图标资源并存储起来即可。除了上面可以参考从DevExpress内置图标资源获取图标的方式外。我们还可以选择自己喜欢的图标资源也就是从系统图标文件中选择自己喜欢的如下界面所示。因此考虑在运行时整合两种不同选择图标的方式。我们先来看看整合后的图表选择界面如下所示包含了运行时刻提取DevExpress内置图标的功能和从系统文件中选择图标的功能。三、运行时提取DevExpress内置图标的功能实现首先我们参考设计时的界面展示来设计一个界面来展示图标信息参考原版的界面设计尽可能贴近即可另外我们自己加入一个从系统选择图标资源的操作。至于图标选中后我们返回对应的Image对象给调用者则通过事件进行处理以便选中后即使更新显示效果。如下所示我们定义一个委托和事件。/// 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); } }然后在内置图标显示中如果触发图标的单击我们就触发事件以便让调用者更新界面显示如下代码所示。foreach (GalleryItem item in items[key]) { item.ItemClick (s, e) { //选择处理 ProcessIconSelected(item.ImageOptions.Image, item.Description); }; }而对于从系统文件加载文件进行显示图标的类似的触发方式。/// 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); } }这样我们在菜单的选择图标的时候就可以触发事件进行获取图表并更新自身了。private void btnSelectIcon_Click(object sender, EventArgs e) { FrmImageGallery dlg new FrmImageGallery(); dlg.OnIconSelected (image, name) { this.txtEmbedIcon.Image image; }; dlg.ShowDialog(); }完成了这些处理我们再次将焦点放在如何提取并展示DevExpress内置图标的身上。为了获取图表资源里面的分类及大小等信息我们需要把图标资源进行一个加载出来然后读取里面的类别和大小、集合等信息。先定义几个变量来承载这些信息。/// summary /// 图标分类 /// /summary public Liststring Categories { get; set; } /// summary /// 图标集合 /// /summary public Liststring Collection { get; set; } /// summary /// 图标尺寸 /// /summary public Liststring Size { get; set; }DevExpress的图标资源在程序集DevExpress.Utils.DxImageAssemblyUtil.ImageAssembly里面因此我们需要对它进行读取并依次对各个资源进行处理。来看看具体的处理代码如下所示。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)这个代码它就是从资源里面进行获取对应的图表资源。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])); }另外根据图表的文件名结构我们通过正则表达式来读取它的对应信息然后把它的大小、类别、集合信息存储起来。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对象放在一个字典类别里面方便按照组别进行展示。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); } }有了这些资源我们对它们进行搜索就显得很方便了如果需要根据文件名或者其他条件进行查询集合的数据提供一个通用的方法即可如下代码所示。/// summary /// 根据条件获取集合 /// /summary /// returns/returns public Dictionarystring, GalleryItemCollection Search(Liststring collection, Liststring categories, Liststring size, string fileName ) { Dictionarystring, GalleryItemCollection dict new Dictionarystring, 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 进行搜索的了不用再次读取程序集并依次分析它速度提供不少的。由于图表资源的处理是比较耗时的我们把整个图标加载的类作为一个静态的对象缓存起来这样下次使用直接从缓存里面拿对应的资源也不用重新加载更好的提高重用的效果了体验更好了。/// summary /// 图标库加载处理 /// /summary public class DXImageGalleryLoader { /// summary /// 图标字典类别集合 /// /summary public Dictionarystring, GalleryItem ImageCollection { get; set; } /// summary /// 图标分类 /// /summary public Liststring Categories { get; set; } /// summary /// 图标集合 /// /summary public Liststring Collection { get; set; } /// summary /// 图标尺寸 /// /summary public Liststring 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.GetCacheItemDXImageGalleryLoader(keyName, delegate () { return new DXImageGalleryLoader().LoadData(); }, new TimeSpan(0, 30, 0));//30分钟过期 return result; } }以上代码通过public static DXImageGalleryLoader Default定义了一个静态的实例属性这样这个 DXImageGalleryLoader 实例只会在程序第一次使用的时候构建并加载图片资源后续都是从缓存里面读取提高响应速度的同时也会记住上次的选择界面内容。以上就是整个功能的处理思路以及一步步的优化处理以便实现功能展示的同时也提高响应速度最终界面就是我们开始的时候介绍的那样。单击或者选中系统图标后 需要设置的按钮或者界面就会及时更新图标展示体验效果还是非常不错的。由于这个界面功能的通用性我把它作为系统界面基础模块放到了我的框架BaseUIDx里面各个系统模块都可以调用了。本文转载自博客园 - 伍华聪

相关新闻