返回首页


{S0}简介
本文将是一个后期的后续我以前的文章,,关于控制类派生自MFC的CCombobox的。它被张贴以来,一些读者问一个类似的分隔符,在C#中的组合框。接触C#编程时,我发现它很容易写出这样的自定义组合框控件在上面的屏幕截图所示。在实施一个组合框的分隔主要的一点是,一个分隔,不应该选择无论是从用户界面或在代码中的逻辑。我们有两个选择:让分隔占据了项目的空间,或让一个项目之间的分隔符驻留没有多余的空间。我喜欢后者,它只是利用项目之间的路线,节省空间为整个组合框。
,由于组合框和列表框从Windows.Forms.ListControl派生,他们有相同的虚拟OnDrawItem()和OnMeasureItem()功能,在我的定制。在这里,加入一个分隔组合框的实施,也可以被应用到列表框中。所以,我现在都SeparatorComboBox和SeparatorListBox,演示给你看到它的屏幕截图。为了简单起见,我只在下面的章节讨论的组合框。使用SeparatorComboBox
假设ComboBox1的是SeparatorComboBox对象。让我们添加一个字符串的项目:
为了您的方便,AddString()仅仅是一个Items.Add包装(组合框)。下一步,设置这样的分隔位置:{C}
在显示的图像,SetSeparator(1)设置一个分隔符之前的项目索引1处的"香蕉"。第二行设置在位置-1,这意味着在最后一个项目设置一个分隔。这就是:前"*"添加/编辑Fruitquot。这是位置,从零开始的索引方法来设置一个分隔。但是,如果您需要更新,插入,删除或排序组合框,然后按位置设置是不恰当的的。我提供了另一种方法,内容设置一个分隔。因此,在这个例子中,而不是使用:

comboBox1.AddString("*Add/Edit Fruit");

comboBox1.SetSeparator(-1);    

您可以设置相关的文本quot的一个分隔; *添加/编辑Fruitquot;这样的:
comboBox1.AddStringWithSeparator("*Add/Edit Fruit");

分隔符总是卡上quot; *添加/编辑Fruitquot;,无论其位置。总之,SeparatorComboBox有三种方法如下:AddString(字符串s):追加一个字符串项,相当于Items.Add(S)。AddStringWithSeparator(字符串s):增加一个分隔符之前的文本字符串项第由一个从零开始的索引位置,或从底部的负SetSeparator(INT POS):添加一个分隔符。
此外,SeparatorComboBox为视觉效果提供了五种可选的属性:的DashStyle SeparatorStyle:设置分隔风格的DashStyle定义,如固,圆点,破折号等默认为DashStyle.Solid。颜色SeparatorColor:设置分隔颜色的颜色定义。默认是Color.Black。INT SeparatorWidth:设置默认单位,如分离器的宽度,以像素为单位。默认值是1。INT SeparatorMargin:设置分隔两端的水平保证金。默认值是1。BOOL AutoAdjustItemHeight:表示是否允许SeparatorWidth基于该项目高度的自动调整。默认值是false。
演示组合框,我呼吁:
comboBox1.SeparatorColor = Color.DarkBlue;

comboBox1.SeparatorWidth = 2;

comboBox1.AutoAdjustItemHeight = true;

我离开SeparatorStyle固体和SeparatorMargin为1。为了使项目之间的间隔,我设置为true AutoAdjustItemHeight。至于在演示列表框,我用SeparatorColor(黑色),SeparatorWidth(1),AutoAdjustItemHeight(假),并调用默认值:
listBox1.SeparatorStyle = DashStyle.Dash;

listBox1.SeparatorMargin = 2;

另外,你可以设置在窗体设计器的属性:
{S1}实现
的主要工作就是重写OnDrawItem(),并​​绘制项目之间的线。然而,在绘图之前,我们应该有信息收集所有分离器的准备。这是_separators的ArrayList,存储所有分离器的职位或蜇的一个异构容器:
public void SetSeparator(int position)

{

    _separators.Add(position);

}



public void AddStringWithSeparator(string s)

{

    Items.Add(s);

    _separators.Add(s);

}

在OnDrawItem(),我搜索_separators,找到匹配当前指数从DrawItemEventArgs参数传递。这是通过比较一个字符串或一个位置:
protected override void OnDrawItem(DrawItemEventArgs e)

{

    if (-1 == e.Index) return;                      // Not selected



    bool sep = false;

    object o;

    for (int i=0; !sep && i<_separators.Count; i++)

    { 

        o = _separators[i];                         // Get a separator



        if (o is string)                            // Set by content

        {

            if ((string)this.Items[e.Index] == o as string) 

                sep = true;                         // Match content

        }

        else                                        // Set by position

        {

            int pos = (int)o;

            if (pos<0) pos += Items.Count; // Negative position, reversed

            if (e.Index == pos) sep = true;         // Match position

        }

    }



    e.DrawBackground();

    Graphics g = e.Graphics;

    int y = e.Bounds.Location.Y +_separatorWidth-1; // Adjust top Location

                                                    // if _separatorWidth>1

    if (sep)

    {

        Pen pen = new Pen(_separatorColor, _separatorWidth);

        pen.DashStyle = _separatorStyle;             // Apply all properties



        g.DrawLine(pen, e.Bounds.Location.X+_separatorMargin, y, 

                    e.Bounds.Location.X+e.Bounds.Width-_separatorMargin, y);

        y++;

    }



    Brush br = DrawItemState.Selected == (DrawItemState.Selected & e.State)? 

        SystemBrushes.HighlightText: new SolidBrush(e.ForeColor);



    g.DrawString((string)Items[e.Index], e.Font, br, e.Bounds.Left, y+1);    



    base.OnDrawItem(e);

}

现在,如果一个项目有一个分隔符,我画一条线沿其_separatorColor,_separatorWidth,_separatorStyle和_separatorMargin属性的边界顶部。最后,无论绘制一个分隔或不,我要自己绘制的项目文本。要自动调整项目的高度,我覆盖OnMeasureItem()这样的:
protected override void OnMeasureItem(MeasureItemEventArgs e)

{

    if (_autoAdjustItemHeight)

        e.ItemHeight += _separatorWidth;



    base.OnMeasureItem(e);

}

警告:由于OnMeasureItem()是每次添加或插入后立即项目,您必须设置SeparatorWidth和AutoAdjustItemHeight权利之前调用AddString()和AddStringWithSeparator()。否则,你不能达到预期的效果。此外,e.ItemHeight是原始项目的高度,您可能会手动初始化代码或在设计师。兴趣点
作为一个派生类,SeparatorComboBox从ComboBox中继承所有市民。在演示中,我创建了一个SelectedIndexChanged事件和处理程序的TextChanged的处理程序,因为我设置的下拉组合框的风格。另外,我添加插入和删除按钮来调用ComboBox的方法。
{S2}
在这里,代码是没有直接使用ComboBox的不同。当试图插入和删除,您可以验证两个不同的分隔符:如果设置的位置,它总是在指定索引枝,如果与内容设置指定的文本上,它总是坚持。
private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)

{

    textBox1.Text = "Selected: " +comboBox1.SelectedItem;

}



private void comboBox1_TextChanged(object sender, System.EventArgs e)

{

    textBox1.Text = "Changed to: " +comboBox1.Text;

}



private void buttonInsert_Click(object sender, System.EventArgs e)

{

    comboBox1.Items.Insert(comboBox1.Items.Count, comboBox1.Text);

}



private void buttonDelete_Click(object sender, System.EventArgs e)

{

    try

    {

        int n = int.Parse(comboBox1.Text);

        if (n>comboBox1.Items.Count-1) throw new Exception();

        comboBox1.Items.RemoveAt(n);

    }

    catch (Exception)

    {

        MessageBox.Show("Please enter a valid index to delete an item.", 

            "Error");

    }

}

这些都只是微不足道的样本。为了满足您的需求,你有微调您的箱子。唯一不满意的方面,我注意到在组合框中,下拉列表的高度,如果AutoAdjustItemHeight设置为true,不能正确计算。这将导致经常出现,即使是用较少的项目,一个垂直滚动条。历史2007年5月28日 - 原始版本发布

回答

评论会员:麦克Hankey 时间:2011/12/14
好写!正是我所需要的。
不要认为白痴;人看,可能无法告诉差异
评论会员:PhillipFromAZ 时间:2011/12/14
控制工作只是我需要它,那就是,直到我需要绑定的数据源列表。下面是我用的代码妥善处理


        protected override void OnDrawItem(DrawItemEventArgs e)

        {

            /* Need a fix for when binding objects

             *    original:

            *        g.DrawString((string)Items[e.Index], e.Font, br, e.Bounds.Left, y+1);	

            */

            g.DrawString(this.GetItemText(this.Items[e.Index]), e.Font, br, e.Bounds.Left, y + 1);

        }

 


好样的!
评论会员:Zuoliu丁 时间:2011/12/14
我同意。这是较为普遍的项目,而不是硬铸造的对象从一个字符串文本。感谢您的关注
评论会员:标记过 时间:2011/12/14
搞好
评论会员:拉维Bhavnani 时间:2011/12/14
。数据绑定是不可能的
也值成员是不可能的定义。你可以修复错误,请
评论会员:Zuoliu丁 时间:2011/12/14
您的控制是好的。但它有一些问题时,我的数据绑定使用数据集
评论会员:拉维Bhavnani 时间:2011/12/14
!首先,一个精心编写的,易于使用的类
感谢
我发现一个错误控制的OnDrawItem()handler.nbsp;如果目前displayed.nbsp控制的下拉列表分隔符应该只被绘制;解决方法是有条件执行分离器图纸和Y坐标computation.nbsp; IOW,修改:

  g.DrawLine (pen,

              e.Bounds.Location.X+_separatorMargin, y,

              e.Bounds.Location.X+e.Bounds.Width-_separatorMargin, y);

  y++;

:

  if (this.DroppedDown) {

      g.DrawLine (pen,

                  e.Bounds.Location.X+_separatorMargin, y,

                  e.Bounds.Location.X+e.Bounds.Width-_separatorMargin, y);

      y++;

}



拉维/
我的新年分辨率:2048 × 1536


ravib(AT)ravib(DOT)COM
评论会员:拉维Bhavnani 时间:2011/12/14
嗨拉维,

尼斯追上!感谢这么多修正此。

Zuoliu
评论会员:Zuoliu丁 时间:2011/12/14
NP 不幸的是,这只是一个局部的修复!

分离器仍然显示在非下拉(不可编辑)时ComboBox的下拉列表中显示的区域。

拉维/
我的新年分辨率:2048 × 1536


ravib(AT)ravib(DOT)COM
评论会员:cormacmiller 时间:2011/12/14
OnDrawItem纠正修复(),以取代这种情况下:

    if (sep)

:

    if (sep && (e.Bounds.Bottom > this.ClientRectangle.Bottom))

拉维/
我的新年分辨率:2048 × 1536


ravib(AT)ravib(DOT)COM
评论会员:Zuoliu丁 时间:2011/12/14
这是伟大的。我没有触及的C#近年来,从那时起,几乎忘了这一切。感谢帮助解决这个问题
评论会员:。mikepc 时间:2011/12/14
。始终调用OnDrawItem开始e.DrawBackground(),以确保控制看起来像它得到了重点

不要划清界线,如果我们在借鉴的组合编辑框部分:
&# 160; BOOL isDrawingEditBox =(e.State DrawItemState.ComboBoxEdit)==
&# 160; DrawItemState.ComboBoxEdit;
&# 160; 如果(SEP isDrawingEditBox!)
评论会员:MarkGladding 时间:2011/12/14
好主意,谢谢!
评论会员:Zuoliu丁 时间:2011/12/14
控制图是坏的,当我们改变字体格式。
e.Bounds()八方返回高度= 13,所以它是不OK
绘图。

佩拉
评论会员:MarkGladding 时间:2011/12/14
!尼斯的工作Zuoliu

下面是一个改进的情侣

1。替换字符串转换调用toString()方法,让你可以与其他对象而不是字符串填充的项目。



如果((字符串)this.Items [e.Index] == O)作为字符串 - >(this.Items [e.Index]的ToString()== O作为字符串)

g.DrawString((字符串)项目[e.Index],e.Font,BR,e.Bounds.Left,Y 1) - > g.DrawString(项目[e.Index]的ToString(),e.​​Font BR,e.Bounds.Left,Y 1)
添加Clear()方法可以去掉,这样的分隔符。
例如

公共无效的清除()
{
Items.Clear()
&# 160; _separators.Clear()
}

再次,本文​​感谢。


马克Gladding,
作者
评论会员:玛丽都 时间:2011/12/14
谢谢,马克,

我同意你的建议,以改善。此外,我不得不提到它的调用pen.Dispose(OnDrawItem结束()),可能在实际的应用程序。

- Zuoliu丁

评论会员:zyprexia2 时间:2011/12/14
感谢,指出这一点!

马克Gladding,
作者
评论会员:贾里德詹姆斯沙利文 时间:2011/12/14
!问候

我很新的C#编程,我想在我的ASP.NET C#中ListBox的Web控件创建一个类似的功能,这可能吗?

非常感谢你!



玛丽都
评论会员:purshi_alur 时间:2011/12/14
,WebControls没有一幅画事件。然而,你可以继承一个DropDownList,并覆盖默认的Render方法的实施,如seperators您更改。

请注意,默认的HTML下拉(选择元素)已经有optgroup"选项",可以用来组项目。据我知道它不可能与CSS样式optgroup元素。集团本身不能被选中。

我用这个例子来重新选择"HTML" - optgroup - 选项"渲染
评论会员:。purshi_alur 时间:2011/12/14
{A7}

{五}
评论会员:purshi_alur 时间:2011/12/14
测试