首页 > 编程 > C# > 正文

Winform开发框架中如何使用DevExpress的内置图标资源

2019-10-29 19:41:07
字体:
来源:转载
供稿:网友

前言

在开发Winform程序界面的时候,我们往往会使用一些较好看的图表,以便能够为我们的程序界面增色,良好的图标设置可以让界面看起来更加美观舒服,而且也比较容易理解,图标我们可以通过一些网站获取各种场景的图标资源,不过本篇随笔主要介绍如何利用DevExpress的内置图标资源来实现界面图标的设置。

下面话不多说了,来一起看看详细的介绍吧

1、设计时刻的图标处理

丰富的图标处理,在菜单、工具栏、树列表等地方,以及按钮等地方,都可以使用,而这些我们可以利用DevExpress的内置图标选择来减轻我们寻找合适图标的烦恼。

Winform,开发框架,DevExpress,图标资源

一些按钮、工具栏等的图标设置,一般是固定的,我们往往可以在设计时刻就指定它,这样我们可以使用本地的图标,也可以使用DevExpress的内置图标。而使用DevExpress内置图标资源的时候,我们可以调出DevExpress的内置图标选择框的。

如下是按钮添加图标方式,操作非常简单,在按钮的右上角小图标上单击一下进入编辑界面,如下所示。

Winform,开发框架,DevExpress,图标资源

然后选择Image按钮,进入图标选择界面,选择内置的DevExpress图标库即可,基本上,只要是DevExpress的原生控件,那么就可以通过这种内置图标的对话框进行图标选择,非常方便。

Winform,开发框架,DevExpress,图标资源

2、运行时刻的图标处理

上面的操作是在设计时候,DevExpress设计器给我们提供很多便利选择内置图标,而在界面运行时刻,想动态处理界面按钮图标,或者树形菜单的图标的时候,就没有这个直接的接口来设置图标了,而我们框架的菜单往往都是需用动态增加的,因此图标的设置也是在运行时刻的。如下面的树列表中,图标就是动态指定的。

Winform,开发框架,DevExpress,图标资源

这些动态的树形菜单,是在权限系统里面动态配置的,菜单的配置界面如下所示。

Winform,开发框架,DevExpress,图标资源

上面的选择图图标就是我们需要动态设置的图标,由于图标资源我们是以图片形式存储在对应的记录里面的,因此使用起来也是比较方便的,我们在配置的时候,获取到对应的图标资源并存储起来即可。

除了上面可以参考从DevExpress内置图标资源获取图标的方式外

Winform,开发框架,DevExpress,图标资源

我们还可以选择我们自己喜欢的图标资源,也就是从系统图标文件中选择自己喜欢的,如下界面所示。

Winform,开发框架,DevExpress,图标资源

因此我考虑在运行时刻整合两种不同选择图标的方式。

我们先来看看我整合后的图表选择界面,如下所示,包含了运行时刻提取DevExpress内置图标的功能和从系统文件中选择图标的功能。

Winform,开发框架,DevExpress,图标资源

3、运行时刻提取DevExpress内置图标的功能实现

首先我们参考设计时刻的界面展示

Winform,开发框架,DevExpress,图标资源

来设计一个界面来展示图标信息

Winform,开发框架,DevExpress,图标资源

参考原版的界面,设计尽可能贴近即可,另外我们自己加入一个从系统选择图标资源的操作。

Winform,开发框架,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);   }  }

这样我们在菜单的选择图标的时候,就可以触发事件进行获取图表并更新自身了。

Winform,开发框架,DevExpress,图标资源

private void btnSelectIcon_Click(object sender, EventArgs e)  {   FrmImageGallery dlg = new FrmImageGallery();   dlg.OnIconSelected += (image, name) =>   {    this.txtEmbedIcon.Image = image;   };   dlg.ShowDialog();  }

完成了这些处理,我们再次将焦点放在如何提取并展示DevExpress内置图标的身上。

Winform,开发框架,DevExpress,图标资源

为了获取图表资源里面的分类及大小等信息,我们需要把图标资源进行一个加载出来,然后读取里面的类别和大小、集合等信息。先定义几个变量来承载这些信息。

/// <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里面,因此我们需要对它进行读取,并依次对各个资源进行处理。

我们来看看具体的处理代码,如下所示。

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 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进行搜索的了,不用再次读取程序集并依次分析它,速度提供不少的。

由于图表资源的处理是比较耗时的,我们把整个图标加载的类作为一个静态的对象缓存起来,这样下次使用直接从缓存里面拿,对应的资源也不用重新加载,更好的提高我们重用的效果了,体验更好了。

/// <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;   }  }

以上代码通过

public static DXImageGalleryLoader Default

定义了一个静态的实例属性,这样这个DXImageGalleryLoader 实例只会在程序第一次使用的时候构建并加载图片资源,后续都是从缓存里面读取,提高响应速度的同时,也会记住上次的选择界面内容。

以上就是整个功能的处理思路,以及一步步的优化处理,以便实现功能展示的同时,也提高响应速度,最终界面就是我们开始的时候介绍的那样。

Winform,开发框架,DevExpress,图标资源

Winform,开发框架,DevExpress,图标资源

单击或者选中系统图标后, 需要设置的按钮或者界面,就会及时更新图标展示,体验效果还是非常不错的。

由于这个界面功能的通用性,我把它作为系统界面基础模块,放到了我的框架BaseUIDx里面,各个系统模块都可以调用了。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对VEVB武林网的支持。


注:相关教程知识阅读请移步到c#教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表