zoukankan      html  css  js  c++  java
  • listbox美化

    http://www.csharpwin.com/csharpresource/5261r2896.shtml

    WinForm程序开发中,ListBox控件是比较常用的一个控件,有时候我们需要一个比较美观的ListBox控件,让用户看ListBox控件显示的信息时比较清晰、形象,我们可以让ListBox控件隔行显示不同的背景色,让每个项显示图标,本文将介绍怎样实现这样的一个ListBox扩展控件。

     

    先来看看最终实现ListBox扩展控件的效果图:

     

    下面我们一步步的来实现这个ListBox扩展控件。首先,我们来明确一下需要完成的功能:

     

    1、 实现ListBox的项隔行显示不同的背景色。

    2、 扩展ListBox的项,让它可以显示图标。

    3、 实现可以更换ListBox边框的颜色。

     

    第一项功能在以前我写的一篇文章《C# WinForm控件美化扩展系列之ListBox中已经介绍过,这里就不介绍了,我们重点介绍后两个功能的实现。

     

    要让ListBox的每个项显示图标,首先我们需要定义一个我们自己的ListBoxExItem类对象来代替原来的ListBox项,ListBoxExItem需要包含三个属性:Image,我们的图标;Text,显示的文本;Tag,项的用户自定义数据。下面看看这个对象的代码:

    [Serializable]
    [TypeConverter(
    typeof(ExpandableObjectConverter))]
    public class ListBoxExItem : IDisposable
    {
    Fields Fields

    private string _text = "ListBoxExItem";
    private Image _image;
    private object _tag;

    #endregion


    Constructors Constructors

    public ListBoxExItem()
    {
    }


    public ListBoxExItem(string text)
    :
    this(text, null)
    {
    }


    public ListBoxExItem(string text, Image image)
    {
    _text
    = text;
    _image
    = image;
    }


    #endregion

    Properties Properties

    [DefaultValue(
    "ImageComboBoxItem")]
    [Localizable(
    true)]
    public string Text
    {
    get { return _text; }
    set { _text = value; }
    }


    [DefaultValue(
    typeof(Image), "null")]
    public Image Image
    {
    get { return _image; }
    set { _image = value; }
    }


    [Bindable(
    true)]
    [Localizable(
    false)]
    [DefaultValue(
    "")]
    [TypeConverter(
    typeof(StringConverter))]
    [DesignerSerializationVisibility(
    DesignerSerializationVisibility.Hidden)]
    public object Tag
    {
    get { return _tag; }
    set { _tag = value; }
    }


    #endregion

    Override Methods Override Methods

    public override string ToString()
    {
    return _text;
    }


    #endregion

    IDisposable 成员 IDisposable 成员

    public void Dispose()
    {
    _image
    = null;
    _tag
    = null;
    }


    #endregion
    }
     

    实现了ListBoxExItem类对象,我们还需要实现一个ListBoxExItemCollection集合,这个集合需要实现IList、ICollection和IEnumerable接口,用来存储ListBoxExItem对象,像ListBox自己实现的ListBox.ObjectCollection集合那样,我们需要实现一些添加项、删除项等等的一些方法,看看这个集合类的视图和代码:

     


     

    ListBoxExItemCollection 类视图 
     

    ListBoxExItemCollection 类源码:

    [ListBindable(false)]
    public class ListBoxExItemCollection
    : IList,ICollection,IEnumerable
    {
    Fields Fields

    private ListBoxEx _owner;

    #endregion


    Constructors Constructors

    public ListBoxExItemCollection(ListBoxEx owner)
    {
    _owner
    = owner;
    }


    #endregion

    Properties Properties

    internal ListBoxEx Owner
    {
    get { return _owner; }
    }


    public ListBoxExItem this[int index]
    {
    get { return Owner.OldItems[index] as ListBoxExItem; }
    set { Owner.OldItems[index] = value; }
    }


    public int Count
    {
    get { return Owner.OldItems.Count; }
    }


    public bool IsReadOnly
    {
    get { return Owner.OldItems.IsReadOnly; }
    }


    #endregion

    Public Methods Public Methods

    public int Add(ListBoxExItem item)
    {
    if (item == null)
    {
    throw new ArgumentNullException("item");
    }

    return Owner.OldItems.Add(item);
    }


    public void AddRange(ListBoxExItemCollection value)
    {
    foreach (ListBoxExItem item in value)
    {
    Add(item);
    }

    }


    public void AddRange(ListBoxExItem[] items)
    {
    Owner.OldItems.AddRange(items);
    }


    public void Clear()
    {
    Owner.OldItems.Clear();
    }


    public bool Contains(ListBoxExItem item)
    {
    return Owner.OldItems.Contains(item);
    }


    public void CopyTo(
    ListBoxExItem[] destination,
    int arrayIndex)
    {
    Owner.OldItems.CopyTo(destination, arrayIndex);
    }


    public int IndexOf(ListBoxExItem item)
    {
    return Owner.OldItems.IndexOf(item);
    }


    public void Insert(int index, ListBoxExItem item)
    {
    if (item == null)
    {
    throw new ArgumentNullException("item");
    }

    Owner.OldItems.Insert(index, item);
    }


    public void Remove(ListBoxExItem item)
    {
    Owner.OldItems.Remove(item);
    }


    public void RemoveAt(int index)
    {
    Owner.OldItems.RemoveAt(index);
    }


    public IEnumerator GetEnumerator()
    {
    return Owner.OldItems.GetEnumerator();
    }


    #endregion

    IList 成员 IList 成员

    int IList.Add(object value)
    {
    if (!(value is ListBoxExItem))
    {
    throw new ArgumentException();
    }

    return Add(value as ListBoxExItem);
    }


    void IList.Clear()
    {
    Clear();
    }


    bool IList.Contains(object value)
    {
    return Contains(value as ListBoxExItem);
    }


    int IList.IndexOf(object value)
    {
    return IndexOf(value as ListBoxExItem);
    }


    void IList.Insert(int index, object value)
    {
    if (!(value is ListBoxExItem))
    {
    throw new ArgumentException();
    }

    Insert(index, value
    as ListBoxExItem);
    }


    bool IList.IsFixedSize
    {
    get { return false; }
    }


    bool IList.IsReadOnly
    {
    get { return IsReadOnly; }
    }


    void IList.Remove(object value)
    {
    Remove(value
    as ListBoxExItem);
    }


    void IList.RemoveAt(int index)
    {
    RemoveAt(index);
    }


    object IList.this[int index]
    {
    get
    {
    return this[index];
    }

    set
    {
    if (!(value is ListBoxExItem))
    {
    throw new ArgumentException();
    }

    this[index] = value as ListBoxExItem;
    }

    }


    #endregion

    ICollection 成员 ICollection 成员

    void ICollection.CopyTo(Array array, int index)
    {
    CopyTo((ListBoxExItem[])array, index);
    }


    int ICollection.Count
    {
    get { return Count; }
    }


    bool ICollection.IsSynchronized
    {
    get { return false; }
    }


    object ICollection.SyncRoot
    {
    get { return this; }
    }


    #endregion

    IEnumerable 成员 IEnumerable 成员

    IEnumerator IEnumerable.GetEnumerator()
    {
    return GetEnumerator();
    }


    #endregion
    }

     

    准备工作做好了,现在我们来动一动ListBox了,先给它加一个OldItems属性,表示的是它原来的Items属性,然后我们需要用我们自己定义的ListBoxExItemCollection集合来定义一个Items属性,覆盖原来的Items属性,这样在设计的时候就是设计我们自己定义的ListBoxExItem项了,我们就可以设置我们自己的项的图标和文本了。看看这两个属性的定义:

    internal ListBox.ObjectCollection OldItems
    {
    get { return base.Items; }
    }

    [Localizable(true)]
    [MergableProperty(
    false)]
    [DesignerSerializationVisibility(
    DesignerSerializationVisibility.Content)]
    public new ListBoxExItemCollection Items
    {
    get { return _items; }
    }

     

    最后就是DrawItem了,我们直接用我们自己自定义的Items就可以获取需要绘制的ListBoxExItem项了,我们把图标和文本绘好就OK了。看看绘制的代码:

    protected override void OnDrawItem(DrawItemEventArgs e)
    {
    base.OnDrawItem(e);

    if (e.Index != -1 && base.Items.Count > 0)
    {
    System.Diagnostics.Debug.WriteLine(e.State);
    Rectangle bounds
    = e.Bounds;
    ListBoxExItem item
    = Items[e.Index];
    Graphics g
    = e.Graphics;

    if ((e.State & DrawItemState.Selected)
    == DrawItemState.Selected)
    {
    RenderBackgroundInternal(
    g,
    bounds,
    _selectedColor,
    _selectedColor,
    Color.FromArgb(
    200, 255, 255, 255),
    0.45f,
    true,
    LinearGradientMode.Vertical);
    }

    else
    {
    Color backColor;
    if (e.Index % 2 == 0)
    {
    backColor
    = _rowBackColor2;
    }

    else
    {
    backColor
    = _rowBackColor1;
    }

    using (SolidBrush brush = new SolidBrush(backColor))
    {
    g.FillRectangle(brush, bounds);
    }

    }


    Image image
    = item.Image;

    Rectangle imageRect
    = new Rectangle(
    bounds.X
    + 2,
    bounds.Y
    + 2,
    bounds.Height
    - 4,
    bounds.Height
    - 4);
    Rectangle textRect
    = new Rectangle(
    imageRect.Right
    + 2,
    bounds.Y,
    bounds.Width
    - imageRect.Right - 2,
    bounds.Height);

    string text = item.ToString();
    TextFormatFlags formatFlags
    =
    TextFormatFlags.VerticalCenter;
    if (RightToLeft == RightToLeft.Yes)
    {
    imageRect.X
    = bounds.Right - imageRect.Right;
    textRect.X
    = bounds.Right - textRect.Right;
    formatFlags
    |= TextFormatFlags.RightToLeft;
    formatFlags
    |= TextFormatFlags.Right;
    }

    else
    {
    formatFlags
    |= TextFormatFlags.Left;
    }


    if (image != null)
    {
    g.InterpolationMode
    =
    InterpolationMode.HighQualityBilinear;
    g.DrawImage(
    image,
    imageRect,
    0,
    0,
    image.Width,
    image.Height,
    GraphicsUnit.Pixel);
    }


    TextRenderer.DrawText(
    g,
    text,
    Font,
    textRect,
    ForeColor,
    v formatFlags);

    if ((e.State & DrawItemState.Focus) ==
    DrawItemState.Focus)
    {
    e.DrawFocusRectangle();
    }

    }

    }

     

    接下来开始换ListBox控件的边框颜色,这个功能需要用到一些API函数,简单的介绍一下实现的原理,首先我们需要获取ListBox控件非客户区的区域,这个需要注意的地方是需要排除滚动条的区域,应为这个区域系统会自己绘制滚动条的,我们不需要处理。获取非客户区域后,我们就用ListBox控件的背景色来填充它,然后再绘制边框,这些绘制需要在WM_NCPAINT消息中绘制,具体的实现大家可以下载源码看,由于涉及的源码比较多,这里就不贴源码了。

     

    好了,现在整个ListBox控件的扩展和美化就完成了,希望你能喜欢,也希望对你有所帮助。最后希望大家继续支持CS程序员之窗。

  • 相关阅读:
    关于TileBrush中Viewbox,Viewport以及Stretch,AlignmentX/Y的详细研究
    ListBox数据绑定无效
    WPF---Effect效果
    wpf 画刷的分类
    LinearGradientBrush,RadialGradientBrush的样式说明
    改变ListBoxItem选中的颜色
    自定义的 ListBoxItem 自适应ListBox的宽度
    WPF ListBox数据绑定
    ItemsPanelTemplate的用法
    svn报错Item is not readable svn解决方案
  • 原文地址:https://www.cnblogs.com/superstar/p/1769809.html
Copyright © 2011-2022 走看看