C# WinForm控件美化扩展系列之ImageComboBox_C# 视角_CS程序员之窗

前面介绍了两篇关于ComboBox扩展和美化的文章:C# WinForm控件美化扩展系列之ComboBox组合框控件C# WinForm控件美化扩展系列之给ComboBox加水印,今天将在前两篇的基础上实现一个ImageComboBox控件,ImageComboBox控件拥有以下功能:

(1)  美化下拉按钮和边框,前面的文章已经实现。

(2)  当ComboBox没有控件选择项和没有焦点时显示提示用户操作信息,前面的也文章已经实现。

(3)  在下拉列表框的项中显示图标,项可以缩进。

(4)  在ComboBox控件中也显示图标。

 

来看看最终需要实现的效果:

 

图1 ImageComboBox DropDownList效果
 


 

图2 ImageComboBox DropDown效果
 




这篇文章中我们重点需要实现的是(3)、(4)两项功能,下面我们来介绍具体实现的方法。

 

第一步,实现ImageComboBoxItem类。

要实现显示图标,当然要给每个项添加与图标相关的信息了,ImageComboBoxItem类应该包括以下内容:文本(Text)、缩进的级别(Level)、图标的索引(ImageIndex、ImageKey),用户数据(Tag)。ImageComboBoxItem类实现了ISerializable接口,实现自定义序列化。ImageComboBoxItem类的类视图如下:

 

图3 ImageComboxItem类视图


 

ImageComboBoxItem类的代码如下: 

    [Serializable]


    [DefaultProperty("Text")]


    [TypeConverter(


        typeof(ExpandableObjectConverter))]


    public class ImageComboBoxItem :


        IDisposable, ISerializable


    {


        Fields



        Constructors



        Properties



        Methods



        ISerializable 成员



        IDisposable 成员



        ImageComboBoxItemImageIndexer Class


    }

 

第二步,实现ImageComboBoxItemCollection类。

ImageComboBoxItemCollection类实现跟ComboBox.ObjectCollection类一样的功能,用来代替ComboBox控件中ComboBox.ObjectCollection类,定义一个新的Items来存储ImageComboBoxItem对象,来实现ImageComboBox控件设计时可以支持ImageComboBoxItem对象的设计。

 

第三步,给ImageComboBox控件添加一些属性。

ImageComboBox控件主要需要添加几个属性:图标集合(ImageList)、没有选择项时ComboBox中显示的默认图标(DefaultImage)、缩进值(Indent)、提示信息(EmptyTextTip)、提示信息的文本颜色(EmptyTextTipColor)。还需要覆盖一些属性,这里不一一列出了,看下面的ImageComboBox控件的类视图:

 

图4 ImageComboBox类视图

第四步,实现EditorNativeWimdow类。

EditorNativeWimdow类的主要功能是实现当ImageComboBox控件的列表模式设为非DropDownList的时候,即DropDownStyle不是ComboBoxStyle.DropDownList的时候,实现在Editor中绘制图标。EditorNativeWimdow类的代码如下: 

private class EditorNativeWimdow


    : NativeWindow, IDisposable


{


    Fields



    Constructors



    Private Methods



    IDisposable 成员


}

第五步,重写OnCreateControl、OnHandleDestroyed方法。

重写这两个方法主要是为了ImageComboBox控件的DropDownStyle为不同的值时,控制是否需要在Editor中绘制图标,这两个方法的代码如下: 

protected override void OnCreateControl()


{


    base.OnCreateControl();


    if (DropDownStyle != ComboBoxStyle.DropDownList &&


        !DesignMode)


    {


        if (_nativeWimdow == null)


        {


            _nativeWimdow = new EditorNativeWimdow(this);


        }


    }


}



protected override void OnHandleDestroyed(EventArgs e)


{


    if (_nativeWimdow != null)


    {


        _nativeWimdow.Dispose();


        _nativeWimdow = null;


    }


    base.OnHandleDestroyed(e);


}

第六步,重写OnDropDown方法。

重写这个方法是为了实现调节下拉列表框显示的大小,因为画了图标,以免项显示不完全。OnDropDown方法代码如下: 

protected override void OnDropDown(


   EventArgs e)


{


    base.OnDropDown(e);



    int ddWidth = 0;


    int textWidth = 0;


    int itemWidth = 0;


    int scrollBarWidth =


        Items.Count > MaxDropDownItems ?


           SystemInformation.VerticalScrollBarWidth :


           0;


    Graphics g = CreateGraphics();



    foreach (ImageComboBoxItem item in Items)


    {


        textWidth = g.MeasureString(


            item.Text, Font).ToSize().Width;


        itemWidth =


            textWidth +


            ItemHeight + 8 +


            _indent * item.Level +


            scrollBarWidth;



        if (itemWidth > ddWidth)


            ddWidth = itemWidth;


    }



    DropDownWidth = (ddWidth > Width) ?


        ddWidth : Width;


    g.Dispose();


}

 

第七步,重绘列表项,让其缩进和显示图标。

重绘列表项,需要把ImageComboBox控件的DrawMode设为DrawMode.OwnerDrawFixed,然后通过重写OnDrawItem方法实现,具体代码如下: 

protected override void OnDrawItem(DrawItemEventArgs e)


{


    if (e.Index != -1)


    {


        ImageComboBoxItem item = Items[e.Index];


        Graphics g = e.Graphics;


        Rectangle bounds = e.Bounds;



        int indentOffset = Indent * item.Level;



        if ((e.State & DrawItemState.ComboBoxEdit) ==


            DrawItemState.ComboBoxEdit)


        {


            indentOffset = 0;


        }



        int imageWidth = bounds.Height;


        Rectangle imageRect;


        Rectangle textRect;


        TextFormatFlags format =


            TextFormatFlags.VerticalCenter |


            TextFormatFlags.SingleLine |


            TextFormatFlags.WordBreak;



        imageRect = new Rectangle(


            bounds.Left + indentOffset + 2,


            bounds.Top,


            imageWidth,


            imageWidth);


        textRect = new Rectangle(


            imageRect.Right + 3,


            bounds.Y,


            bounds.Width - imageRect.Width - indentOffset - 5,


            bounds.Height);



        Rectangle backRect = new Rectangle(


           textRect.X,


           textRect.Y + 1,


           textRect.Width,


           textRect.Height - 2);



        backRect.Width = TextRenderer.MeasureText(


            item.Text, e.Font, textRect.Size, format).Width;



        if (base.RightToLeft == RightToLeft.Yes)


        {


            imageRect.X = bounds.Right - imageRect.Right;


            textRect.X = bounds.Right - textRect.Right;


            backRect.X = textRect.Right - backRect.Width;


        }



        bool selected = ((e.State & DrawItemState.Selected) ==


            DrawItemState.Selected);



        Color backColor = selected ?


            SystemColors.Highlight : base.BackColor;



        using (Brush backBrush = new SolidBrush(backColor))


        {


            g.FillRectangle(backBrush, backRect);


        }



        if (selected)


        {


            ControlPaint.DrawFocusRectangle(


                g,


                backRect);


        }



        Image image = item.Image;


        if (image != null)


        {


            using (InterpolationModeGraphics graphics =


                new InterpolationModeGraphics(


                g, InterpolationMode.HighQualityBicubic))


            {


                if (selected)


                {


                    IntPtr hIcon = NativeMethods.ImageList_GetIcon(


                       ImageList.Handle,


                       item.ImageIndexer.ActualIndex,


                       (int)NativeMethods.ImageListDrawFlags.ILD_SELECTED);


                    g.DrawIcon(Icon.FromHandle(hIcon), imageRect);


                    NativeMethods.DestroyIcon(hIcon);


                }


                else


                {


                    g.DrawImage(


                        image,


                        imageRect,


                        0,


                        0,


                        image.Width,


                        image.Height,


                        GraphicsUnit.Pixel);


                }


            }


        }



        TextRenderer.DrawText(


            g,


            item.Text,


            e.Font,


            textRect,


            base.ForeColor,


            format);


    }


}

 

到此为止,ImageComboBox控件需要实现的功能就完成了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这篇文章中我们重点需要实现的是(3)、(4)两项功能,下面我们来介绍具体实现的方法。 第一步,实现ImageComboBoxItem类。 要实现显示图标,当然要给每个项添加与图标相关的信息了,ImageComboBoxItem类应该包括以下内容:文本(Text)、缩进的级别(Level)、图标的索引(ImageIndex、ImageKey),用户数据(Tag)。ImageComboBoxItem类实现了ISerializable接口,实现自定义序列化。ImageComboBoxItem类的类视图如下: 图3 ImageComboxItem类视图 ImageComboBoxItem类的代码如下: [Serializable] [DefaultProperty("Text")] [TypeConverter( typeof(ExpandableObjectConverter))] public class ImageComboBoxItem : IDisposable, ISerializable ...{ Fields#region Fields private ImageComboBox _imageComboBox; private string _text = "ImageComboBoxItem"; private ImageComboBoxItemImageIndexer _imageIndexer; private object _tag; private int _level; #endregion Constructors#region Constructors public ImageComboBoxItem() ...{ } public ImageComboBoxItem(string text) : this(text, -1, 0) ...{ } public ImageComboBoxItem( string text, int imageIndex) : this(text, imageIndex, 0) ...{ } public ImageComboBoxItem( string text, string imageKey) : this(text, imageKey, 0) ...{ } public ImageComboBoxItem( string text, int imageIndex, int level) : this() ...{ _text = text; ImageIndexer.Index = imageIndex; _level = level; } public ImageComboBoxItem( string text, string imageKey, int level) : this() ...{ _text = text; ImageIndexer.Key = imageKey; _level = level; } protected ImageComboBoxItem( SerializationInfo info, StreamingContext context) : this() ...{ Deserialize(info, context); } #endregion Properties#region Properties [Localizable(true)]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值