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

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

一、设计时刻的图标处理

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

一些按钮、工具栏等的图标设置,通常是固定的,咱们每每能够在设计时刻就指定它,这样咱们可使用本地的图标,也可使用DevExpress的内置图标。而使用DevExpress内置图标资源的时候,咱们能够调出DevExpress的内置图标选择框的。缓存

 以下是按钮添加图标方式,操做很是简单,在按钮的右上角小图标上单击一下进入编辑界面,以下所示。框架

而后选择Image按钮,进入图标选择界面,选择内置的DevExpress图标库便可,基本上,只要是DevExpress的原生控件,那么就能够经过这种内置图标的对话框进行图标选择,很是方便。ide

 

二、运行时刻的图标处理

上面的操做是在设计时候,DevExpress设计器给咱们提供不少便利选择内置图标,而在界面运行时刻,想动态处理界面按钮图标,或者树形菜单的图标的时候,就没有这个直接的接口来设置图标了,而咱们框架的菜单每每都是需用动态增长的,所以图标的设置也是在运行时刻的。以下面的树列表中,图标就是动态指定的。工具

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

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

除了上面能够参考从DevExpress内置图标资源获取图标的方式外网站

咱们还能够选择咱们本身喜欢的图标资源,也就是从系统图标文件中选择本身喜欢的,以下界面所示。this

所以我考虑在运行时刻整合两种不一样选择图标的方式。

咱们先来看看我整合后的图表选择界面,以下所示,包含了运行时刻提取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 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 实例只会在程序第一次使用的时候构建并加载图片资源,后续都是从缓存里面读取,提升响应速度的同时,也会记住上次的选择界面内容。

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

 

单击或者选中系统图标后, 须要设置的按钮或者界面,就会及时更新图标展现,体验效果仍是很是不错的。

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

 

 

出处:https://www.cnblogs.com/wuhuacong/p/10095661.html

相关文章
相关标签/搜索