WinForms TreeView具有收音机和复选框
我希望TreeView能够在多个根节点上显示单选按钮,并在其子节点上显示复选框。任何根节点下只有一级子节点 收音机的行为也应类似于一个组,即选择一个根,取消选择其他的收音机 我一直试图用图像来伪装它,但它看起来不真实。我最初有一个列表框和一个单独的checkedlistbox,但可用性之神将其删除了 是否有人实现了此功能或有其他建议 这样想: (o) 麦当劳WinForms TreeView具有收音机和复选框,winforms,checkbox,radio-button,Winforms,Checkbox,Radio Button,我希望TreeView能够在多个根节点上显示单选按钮,并在其子节点上显示复选框。任何根节点下只有一级子节点 收音机的行为也应类似于一个组,即选择一个根,取消选择其他的收音机 我一直试图用图像来伪装它,但它看起来不真实。我最初有一个列表框和一个单独的checkedlistbox,但可用性之神将其删除了 是否有人实现了此功能或有其他建议 这样想: (o) 麦当劳 []汉堡 []炸薯条 []饮料 (o) 汉堡王 []汉堡 []炸薯条 []饮料 (*)温迪的 [x] 汉堡 [x] 炸薯条 []饮料 您可
[]汉堡
[]炸薯条
[]饮料
(o) 汉堡王
[]汉堡
[]炸薯条
[]饮料
(*)温迪的
[x] 汉堡
[x] 炸薯条
[]饮料
您可以有一个大选项,但在大选项下选择1..n。我根据本文提出了一个解决方案。我的实现继承自CheckedListBox,包括以下方法:
protected override void OnDrawItem (DrawItemEventArgs e)
{
// Erase all background if control has no items
if (e.Index < 0 || e.Index > this.Items.Count - 1)
{
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
return;
}
// Calculate bounds for background, if last item paint up to bottom of control
Rectangle rectBack = e.Bounds;
if (e.Index == this.Items.Count - 1)
rectBack.Height = this.ClientRectangle.Top + this.ClientRectangle.Height - e.Bounds.Top;
e.Graphics.FillRectangle(new SolidBrush(this.BackColor), rectBack);
// Determines text color/brush
Brush brushText = SystemBrushes.FromSystemColor(this.ForeColor);
if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled || (e.State & DrawItemState.Grayed) == DrawItemState.Grayed)
brushText = SystemBrushes.GrayText;
Boolean bIsChecked = this.GetItemChecked(e.Index);
String strText;
if (!string.IsNullOrEmpty(DisplayMember)) // Bound Datatable? Then show the column written in Displaymember
strText = ((System.Data.DataRowView) this.Items[e.Index])[this.DisplayMember].ToString();
else
strText = this.Items[e.Index].ToString();
Size sizeGlyph;
Point ptGlyph;
if (this.GetItemType(e.Index) == ItemType.Radio)
{
RadioButtonState stateRadio = bIsChecked ? RadioButtonState.CheckedNormal : RadioButtonState.UncheckedNormal;
if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled || (e.State & DrawItemState.Grayed) == DrawItemState.Grayed)
stateRadio = bIsChecked ? RadioButtonState.CheckedDisabled : RadioButtonState.UncheckedDisabled;
// Determines bounds for text and radio button
sizeGlyph = RadioButtonRenderer.GetGlyphSize(e.Graphics, stateRadio);
ptGlyph = e.Bounds.Location;
ptGlyph.X += 4; // a comfortable distance from the edge
ptGlyph.Y += (e.Bounds.Height - sizeGlyph.Height) / 2;
// Draws the radio button
RadioButtonRenderer.DrawRadioButton(e.Graphics, ptGlyph, stateRadio);
}
else
{
CheckBoxState stateCheck = bIsChecked ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal;
if ((e.State & DrawItemState.Disabled) == DrawItemState.Disabled || (e.State & DrawItemState.Grayed) == DrawItemState.Grayed)
stateCheck = bIsChecked ? CheckBoxState.CheckedDisabled : CheckBoxState.UncheckedDisabled;
// Determines bounds for text and radio button
sizeGlyph = CheckBoxRenderer.GetGlyphSize(e.Graphics, stateCheck);
ptGlyph = e.Bounds.Location;
ptGlyph.X += 20; // a comfortable distance from the edge
ptGlyph.Y += (e.Bounds.Height - sizeGlyph.Height) / 2;
// Draws the radio button
CheckBoxRenderer.DrawCheckBox(e.Graphics, ptGlyph, stateCheck);
}
// Draws the text
Rectangle rectText = new Rectangle(ptGlyph.X + sizeGlyph.Width + 3, e.Bounds.Y, e.Bounds.Width - sizeGlyph.Width, e.Bounds.Height);
e.Graphics.DrawString(strText.Substring(4), e.Font, brushText, rectText, this.oAlign);
// If the ListBox has focus, draw a focus rectangle around the selected item.
e.DrawFocusRectangle();
}
protected override void OnItemCheck (ItemCheckEventArgs ice)
{
base.OnItemCheck(ice);
if (ice.NewValue == CheckState.Unchecked)
return;
if (this.GetItemType(ice.Index) == ItemType.Radio) // if they selected a root, deselect other roots and their children
{
for (Int32 i = 0; i < this.Items.Count; ++i)
{
if (i == ice.Index)
continue;
if (this.GetItemType(i) == ItemType.Radio)
{
this.SetItemChecked(i, false);
Int32 j = i + 1;
while (j < this.Items.Count && this.GetItemType(j) == ItemType.Checkbox)
{
this.SetItemChecked(j, false);
j++;
}
}
}
}
else if (this.GetItemType(ice.Index) == ItemType.Checkbox) // they selected a child; select the root too and deselect other roots and their children
{
// Find parent
Int32 iParentIdx = ice.Index - 1;
while (iParentIdx >= 0 && this.GetItemType(iParentIdx) == ItemType.Checkbox)
iParentIdx--;
this.SetItemChecked(iParentIdx, true);
}
}
protected ItemType GetItemType (Int32 iIdx)
{
String strText = this.Items[iIdx].ToString();
if (strText.StartsWith("(o)"))
return (ItemType.Radio);
else if (strText.StartsWith("[x]"))
return (ItemType.Checkbox);
throw (new Exception("Invalid item type"));
}
受保护的覆盖无效OnDrawItem(DrawItemEventArgs e)
{
//如果控件没有任何项,则清除所有背景
如果(e.Index<0 | | e.Index>this.Items.Count-1)
{
e、 Graphics.FillRectangle(新的SolidBrush(this.BackColor)、this.ClientRectangle);
返回;
}
//如果最后一项绘制到控件底部,则计算背景的边界
矩形矩形矩形=e.边界;
if(e.Index==this.Items.Count-1)
rectBack.Height=this.ClientRectangle.Top+this.ClientRectangle.Height-e.Bounds.Top;
e、 Graphics.FillRectangle(新的SolidBrush(this.BackColor),rectBack);
//确定文本颜色/画笔
Brush brushText=SystemBrush.FromSystemColor(this.ForeColor);
if((e.State&DrawItemState.Disabled)=DrawItemState.Disabled | | |(e.State&DrawItemState.Grayed)==DrawItemState.Grayed)
brushText=systembrushs.GrayText;
Boolean bIsChecked=this.GetItemChecked(e.Index);
字符串strText;
如果(!string.IsNullOrEmpty(DisplayMember))//绑定的Datatable?则显示在DisplayMember中写入的列
strText=((System.Data.DataRowView)this.Items[e.Index])[this.DisplayMember].ToString();
其他的
strText=this.Items[e.Index].ToString();
大小;
点字形;
if(this.GetItemType(e.Index)==ItemType.Radio)
{
RadioButtonState状态Radio=bIsChecked?RadioButtonState.CheckedNormal:RadioButtonState.UncheckedNormal;
if((e.State&DrawItemState.Disabled)=DrawItemState.Disabled | | |(e.State&DrawItemState.Grayed)==DrawItemState.Grayed)
stateRadio=bIsChecked?RadioButtonState.CheckedDisabled:RadioButtonState.UncheckedDisabled;
//确定文本和单选按钮的边界
sizeGlyph=RadioButtonRenderer.GetGlyphSize(例如图形、stateRadio);
ptGlyph=e.Bounds.Location;
ptGlyph.X+=4;//与边缘的舒适距离
ptGlyph.Y+=(e.Bounds.Height-sizeGlyph.Height)/2;
//绘制单选按钮
RadioButtonRenderer.DrawRadioButton(例如图形、ptGlyph、stateRadio);
}
其他的
{
CheckBoxState stateCheck=bIsChecked?CheckBoxState.CheckedNormal:CheckBoxState.UncheckedNormal;
if((e.State&DrawItemState.Disabled)=DrawItemState.Disabled | | |(e.State&DrawItemState.Grayed)==DrawItemState.Grayed)
stateCheck=bIsChecked?CheckBoxState.CheckedDisabled:CheckBoxState.UncheckedDisabled;
//确定文本和单选按钮的边界
sizeGlyph=CheckBoxRenderer.GetGlyphSize(如图形、状态检查);
ptGlyph=e.Bounds.Location;
ptGlyph.X+=20;//与边缘的舒适距离
ptGlyph.Y+=(e.Bounds.Height-sizeGlyph.Height)/2;
//绘制单选按钮
DrawCheckBox(例如图形、ptGlyph、状态检查);
}
//绘制文本
矩形矩形文本=新矩形(ptGlyph.X+sizeGlyph.Width+3,e.Bounds.Y,e.Bounds.Width-sizeGlyph.Width,e.Bounds.Height);
e、 Graphics.DrawString(strText.Substring(4),例如Font、brushText、rectText、this.oAlign);
//如果列表框具有焦点,请围绕选定项绘制一个焦点矩形。
e、 DrawFocusRectangle();
}
受保护的覆盖检查(ItemCheckEventArgs ice)
{
基部。麦切克(冰);
if(ice.NewValue==CheckState.Unchecked)
返回;
if(this.GetItemType(ice.Index)=ItemType.Radio)//如果他们选择了根,则取消选择其他根及其子根
{
对于(Int32 i=0;i=0&&this.GetItemType(iParentIdx)==ItemType.Checkbox)
iParentIdx--;
this.SetItemChecked(iParentIdx,true);
}
}
受保护的ItemType GetItemType(Int32 iIdx)
{
字符串strText=this.Items[iIdx].ToString();
if(strText.StartsWith(“(o)”)
返回(ItemType.Ra)