清除C#窗体上所有控件的最佳方法是什么?

17

我记得有人一段时间之前问过类似的问题,但是我做了搜索却没有找到任何内容。

我正在尝试想出将表单上的所有控件清除回到它们的默认值的最简洁方法(例如,清除文本框,取消复选框勾选)。

您会如何处理这个问题?

9个回答

21
我想到的东西大致如下:
public static class extenstions
{
    private static Dictionary<Type, Action<Control>> controldefaults = new Dictionary<Type, Action<Control>>() { 
            {typeof(TextBox), c => ((TextBox)c).Clear()},
            {typeof(CheckBox), c => ((CheckBox)c).Checked = false},
            {typeof(ListBox), c => ((ListBox)c).Items.Clear()},
            {typeof(RadioButton), c => ((RadioButton)c).Checked = false},
            {typeof(GroupBox), c => ((GroupBox)c).Controls.ClearControls()},
            {typeof(Panel), c => ((Panel)c).Controls.ClearControls()}
    };

    private static void FindAndInvoke(Type type, Control control) 
    {
        if (controldefaults.ContainsKey(type)) {
            controldefaults[type].Invoke(control);
        }
    }

    public static void ClearControls(this Control.ControlCollection controls)
    {
        foreach (Control control in controls)
        {
             FindAndInvoke(control.GetType(), control);
        }
    }

    public static void ClearControls<T>(this Control.ControlCollection controls) where T : class 
    {
        if (!controldefaults.ContainsKey(typeof(T))) return;

        foreach (Control control in controls)
        {
           if (control.GetType().Equals(typeof(T)))
           {
               FindAndInvoke(typeof(T), control);
           }
        }    

    }

}

现在你只需要像这样调用扩展方法ClearControls:
 private void button1_Click(object sender, EventArgs e)
    {
        this.Controls.ClearControls();
    }

编辑:我刚刚添加了一个通用的ClearControls方法,它可以清除该类型的所有控件,可以像这样调用:

this.Controls.ClearControls<TextBox>();

目前它只能处理顶级控件,而不能深入到分组框和面板中。


4

我知道这是一个老问题,但是我想发表一下我的看法。这是我用于表单清除的辅助类。

using System;
using System.Windows.Forms;

namespace FormClearing
{
    class Helper
    {
        public static void ClearFormControls(Form form)
        {
            foreach (Control control in form.Controls)
            {
                if (control is TextBox)
                {
                    TextBox txtbox = (TextBox)control;
                    txtbox.Text = string.Empty;
                }
                else if(control is CheckBox)
                {
                    CheckBox chkbox = (CheckBox)control;
                    chkbox.Checked = false;
                }
                else if (control is RadioButton)
                {
                    RadioButton rdbtn = (RadioButton)control;
                    rdbtn.Checked = false;
                }
                else if (control is DateTimePicker)
                {
                    DateTimePicker dtp = (DateTimePicker)control;
                    dtp.Value = DateTime.Now;
                }
            }
        }
    }
}

我可以从任何表单中通过传递表单对象作为参数来调用该方法。

Helper.ClearFormControls(this);

你可以将其扩展到其他类型的控件。你只需要进行强制转换。

2
我投票支持Nathan的解决方案,但我想补充一些评论无法处理的内容。
他的方法非常好,但我认为最好的解决方案是在将控件添加到GUI之前对要添加的每种控件进行子类化。让它们都实现一个名为“Clearable”(或类似的)接口(我是Java程序员,但概念应该存在),然后将其作为“Clearable”对象的集合进行迭代,调用唯一的方法.clear()。
这才是面向对象系统中GUI应该完成的方式。这将使您的代码易于在将来扩展 - 几乎太容易了,您会感到震惊。
编辑:(根据Nathan关于不更改现有控件的评论)
也许您可以创建“Container”类来引用您的控件(每种类型的控件一个)。在像您在答案中设置的循环中,您可以实例化正确的容器,将真正的控件放入容器中,并将容器存储在集合中。
这样,您又回到了遍历集合的状态。
这将是一个很好的简单解决方案,比您建议的方法复杂得不多,但可扩展性无限。

一定要在添加控件到项目之前为每个控件创建子类。这样做可以让你稍后更轻松地进行更改。 - Cade Roux
我曾考虑过使用子类的方法,但当时我只是在重构一个旧项目,并不想重新设计用户界面。在未来的项目中,我会尽可能使用子类。 - Nathan W
@Bill 我会考虑你的建议。 - Nathan W

2

这里是我在第一个回答中提出的相同解决方案,但使用VB语言。由于VB不支持lambdas中的无返回函数,在VB10发布前,这是我们能做到的最好的方法:

VB解决方案:

Public Module Extension
    Private Sub ClearTextBox(ByVal T As TextBox)
        T.Clear()
    End Sub

    Private Sub ClearCheckBox(ByVal T As CheckBox)
        T.Checked = False
    End Sub

    Private Sub ClearListBox(ByVal T As ListBox)
        T.Items.Clear()
    End Sub

    Private Sub ClearGroupbox(ByVal T As GroupBox)
        T.Controls.ClearControls()
    End Sub

    <Runtime.CompilerServices.Extension()> _
    Public Sub ClearControls(ByVal Controls As ControlCollection)
        For Each Control In Controls
            If ControlDefaults.ContainsKey(Control.GetType()) Then
                ControlDefaults(Control.GetType()).Invoke(Control)
            End If
        Next
    End Sub

    Private _ControlDefaults As Dictionary(Of Type, Action(Of Control))
    Private ReadOnly Property ControlDefaults() As Dictionary(Of Type, Action(Of Control))
        Get
            If (_ControlDefaults Is Nothing) Then
                _ControlDefaults = New Dictionary(Of Type, Action(Of Control))
                _ControlDefaults.Add(GetType(TextBox), AddressOf ClearTextBox)
                _ControlDefaults.Add(GetType(CheckBox), AddressOf ClearCheckBox)
                _ControlDefaults.Add(GetType(ListBox), AddressOf ClearListBox)
                _ControlDefaults.Add(GetType(GroupBox), AddressOf ClearGroupbox)
            End If
            Return _ControlDefaults
        End Get
    End Property

End Module

调用:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Controls.ClearControls()
    End Sub

我在此发布这篇文章,让大家看看如何在VB中完成同样的事情。

2

您可以使用循环控制

foreach (Control ctrl in this)
{
    if(ctrl is TextBox)
        (ctrl as TextBox).Clear();
}

我曾经使用这种方法,但我想找到一些更少依赖于 if..then..else 的东西。 - Nathan W

2
以上解决方案似乎忽略了嵌套控件。
可能需要使用递归函数,例如:
public void ClearControl(Control control)
{
  TextBox tb = control as TextBox;
  if (tb != null)
  {
    tb.Text = String.Empty;
  }
  // repeat for combobox, listbox, checkbox and any other controls you want to clear
  if (control.HasChildren)
  {
    foreach(Control child in control.Controls)
    {
      ClearControl(child)
    }
  }
}

在清除文本属性之前,您不希望仅仅检查控件类型。

实现一个接口,比如IClearable(像Bill K建议的那样)在一组派生控件上会减少此函数的长度,但需要在每个控件上进行更多的工作。


我提出的解决方案将包括嵌套控件。 - Nathan W
Nathan,那是一个有趣的解决方案。从代码上看,嵌套的部分并不明显,所以我没有注意到它。 - benPearce
你如何从代码后台调用该方法? - SearchForKnowledge

1

私有的无返回值函数 FormReset() { ViewState.Clear(); Response.Redirect(Request.Url.AbsoluteUri.ToString()); }


0

我正在使用这种方法来清除Windows表单上的控件。这是文本框、数字增减器和日期选择器的示例。

 public void Clear()
{
    foreach (var item in this.Controls)
    {
        if (item is TextBox)
        {
            TextBox text = (TextBox)item;
            text.Clear();

            //text.Text = "";
            //text.Text=String.Empty;
            //text.Text = null;
        }
        else if (item is NumericUpDown)
        {
            NumericUpDown numeric = (NumericUpDown)item;
            numeric.Value = 0;
        }
        else if (item is DateTimePicker)
        {
            DateTimePicker dateTimePicker = (DateTimePicker)item;
            dateTimePicker.Value = DateTime.Now;
        }
    }
    //Focus the cursor where you want to 
    txtBookName.Focus();
}

0
以下是我用于清除实现了 ITextBox 接口的控件类型中文本的方法。
我注意到在示例中设置了默认布尔值。我相信您可以修改它以设置布尔组件的默认值。
将 Clear 方法传递给控件类型(TextBox、Label 等)和控件集合,它将清除所有实现 ITextBox 的控件中的文本。
类似这样:
//Clears the textboxes
WebControlUtilities.ClearControls<TextBox>(myPanel.Controls);

Clear方法适用于页面或母版页。控件集合类型可能会有所不同,例如Form、ContentPlaceHolder等。

        /// <summary>
    /// Clears Text from Controls...ie TextBox, Label, anything that implements ITextBox
    /// </summary>
    /// <typeparam name="T">Collection Type, ie. ContentPlaceHolder..</typeparam>
    /// <typeparam name="C">ie TextBox, Label, anything that implements ITextBox</typeparam>
    /// <param name="controls"></param>
    public static void Clear<T, C>(ControlCollection controls)
        where C : ITextControl
        where T : Control
    {
        IEnumerable<T> placeHolders = controls.OfType<T>();
        List<T> holders = placeHolders.ToList();

        foreach (T holder in holders)
        {
            IEnumerable<C> enumBoxes = holder.Controls.OfType<C>();
            List<C> boxes = enumBoxes.ToList();

            foreach (C box in boxes)
            {
                box.Text = string.Empty;
            }
        }
    }

    /// <summary>
    /// Clears the text from control.
    /// </summary>
    /// <typeparam name="C"></typeparam>
    /// <param name="controls">The controls.</param>
    public static void ClearControls<C>(ControlCollection controls) where C : ITextControl
    {
        IEnumerable<C> enumBoxes = controls.OfType<C>();
        List<C> boxes = enumBoxes.ToList();

        foreach (C box in boxes)
        {
            box.Text = string.Empty;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接