WinForms有无线电和复选框的TreeView [英] WinForms TreeView with both radios and checkboxes

查看:106
本文介绍了WinForms有无线电和复选框的TreeView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个案例,我希望TreeView能够显示多个根节点上的单选按钮和他们的孩子的复选框。在任何根节点下只有一级子级。



无线电也应该像一个组一样工作,即选择一个根,取消选择其他的无线电。 / p>

我一直试图用图像伪造它,但它看起来不现实。我原来有一个列表框和一个单独的检查列表框,但可用性上帝击中了它。



有没有人实现这个功能或有另一个建议?



这样想:



(o)McDonalds

    [] Burger < br>
    [] Fries

    []饮料

(o)汉堡王

    [] Burger

    [] Fries

    []饮料

)Wendy的

    [x] Burger

    [x] Fries

   ] Drink



您可以有一个大选项,但在大选项下选择1..n。

解决方案

我想出了一个基于文章的解决方案http://www.codeproject.com/KB/combobox/RadioListBoxDotNetVersion.aspx 。我的实现继承自CheckedListBox并包括以下方法:

  protected override void OnDrawItem(DrawItemEventArgs e)
{
//如果控件没有项目,则擦除所有背景
if(e.Index< 0 || e.Index> this.Items.Count - 1)
{
e。 Graphics.FillRectangle(new SolidBrush(this.BackColor),this.ClientRectangle);
return;
}

//如果最后一个项目绘制到控件的底部,则计算背景的边界
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);

//确定文本颜色/画笔
刷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))//绑定数据表?然后显示写在Displaymember中的列
strText =((System.Data.DataRowView)this.Items [e.Index])[this.DisplayMember] .ToString();
else
strText = this.Items [e.Index] .ToString();

大小sizeGlyph;
Point ptGlyph;

if(this.GetItemType(e.Index)== ItemType.Radio)
{
RadioButtonState stateRadio = bIsChecked? RadioButtonState.UncheckedNormal;
if((e.State& DrawItemState.Disabled)== DrawItemState.Disabled ||(e.State& DrawItemState.Grayed)== DrawItemState.Grayed)
stateRadio = bIsChecked? RadioButtonState.UncheckedDisabled;

//确定文本和单选按钮的边界
sizeGlyph = RadioButtonRenderer.GetGlyphSize(e.Graphics,stateRadio);
ptGlyph = e.Bounds.Location;
ptGlyph.X + = 4; //从边缘的舒适距离
ptGlyph.Y + =(e.Bounds.Height - sizeGlyph.Height)/ 2;

//绘制单选按钮
RadioButtonRenderer.DrawRadioButton(e.Graphics,ptGlyph,stateRadio);
}
else
{
CheckBoxState stateCheck = bIsChecked? CheckBoxState.UncheckedNormal;
if((e.State& DrawItemState.Disabled)== DrawItemState.Disabled ||(e.State& DrawItemState.Grayed)== DrawItemState.Grayed)
stateCheck = bIsChecked? CheckBoxState.UncheckedDisabled;

//确定文本和单选按钮的边界
sizeGlyph = CheckBoxRenderer.GetGlyphSize(e.Graphics,stateCheck);
ptGlyph = e.Bounds.Location;
ptGlyph.X + = 20; //从边缘的舒适距离
ptGlyph.Y + =(e.Bounds.Height - sizeGlyph.Height)/ 2;

//绘制单选按钮
CheckBoxRenderer.DrawCheckBox(e.Graphics,ptGlyph,stateCheck);
}

//绘制文本
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);

//如果ListBox有焦点,在所选项目周围绘制一个焦点矩形。
e.DrawFocusRectangle();
}

protected override void OnItemCheck(ItemCheckEventArgs ice)
{
base.OnItemCheck(ice);

if(ice.NewValue == CheckState.Unchecked)
return;

if(this.GetItemType(ice.Index)== ItemType.Radio)//如果他们选择了一个根,取消选择其他根和他们的孩子
{
for(Int32 i = 0; 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)//他们选择了一个孩子;选择根也取消选择其他根和他们的孩子
{
//查找父
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));
}


I have a case where I would like TreeView to be able to show radio buttons on multiple root nodes, and checkboxes on their children. There would only be one level of children beneath any root node.

The radios should also behave like a group, ie one root is selected and the others' radios deselect.

I've been trying to fake it with images, but it doesn't look realistic. I originally had a listbox and a separate checkedlistbox, but the usability gods struck it down.

Has anyone implemented this functionality or have another suggestion?

Think of it this way:

(o) McDonalds
   [ ] Burger
   [ ] Fries
   [ ] Drink
(o) Burger King
   [ ] Burger
   [ ] Fries
   [ ] Drink
(*) Wendy's
   [x] Burger
   [x] Fries
   [ ] Drink

You can have one big option, but select 1..n underneath the big option.

解决方案

I came up with a solution based on the article http://www.codeproject.com/KB/combobox/RadioListBoxDotNetVersion.aspx. My implementation inherits from CheckedListBox and includes the following methods:

    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"));
    }

这篇关于WinForms有无线电和复选框的TreeView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆