{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日 - 原始版本发布