วิธีรับการควบคุมลูกทั้งหมดของรูปแบบ Windows แบบเฉพาะเจาะจง (ปุ่ม / กล่องข้อความ)


120

ฉันต้องการรับการควบคุมทั้งหมดในแบบฟอร์มที่เป็นประเภท x ฉันค่อนข้างแน่ใจว่าเคยเห็นรหัสนั้นในอดีตที่เคยใช้อะไรแบบนี้:

dim ctrls() as Control
ctrls = Me.Controls(GetType(TextBox))

ฉันรู้ว่าฉันสามารถทำซ้ำการควบคุมทั้งหมดในการรับเด็กโดยใช้ฟังก์ชันเรียกซ้ำได้ แต่มีอะไรที่ง่ายกว่าหรือตรงไปตรงมามากกว่านี้หรือไม่อาจเป็นดังนี้

Dim Ctrls = From ctrl In Me.Controls Where ctrl.GetType Is Textbox

1
คำถามที่เกี่ยวข้อง: stackoverflow.com/questions/253937/…
JYelton

คำตอบ:


232

นี่เป็นอีกทางเลือกหนึ่งสำหรับคุณ ฉันทดสอบโดยการสร้างแอปพลิเคชันตัวอย่างจากนั้นใส่ GroupBox และ GroupBox ไว้ใน GroupBox เริ่มต้น ภายใน GroupBox ที่ซ้อนกันฉันใส่ตัวควบคุมกล่องข้อความ 3 ตัวและปุ่ม นี่คือรหัสที่ฉันใช้ (รวมถึงการเรียกซ้ำที่คุณกำลังมองหา)

public IEnumerable<Control> GetAll(Control control,Type type)
{
    var controls = control.Controls.Cast<Control>();

    return controls.SelectMany(ctrl => GetAll(ctrl,type))
                              .Concat(controls)
                              .Where(c => c.GetType() == type);
}

ในการทดสอบในเหตุการณ์การโหลดแบบฟอร์มฉันต้องการนับการควบคุมทั้งหมดภายใน GroupBox เริ่มต้น

private void Form1_Load(object sender, EventArgs e)
{
    var c = GetAll(this,typeof(TextBox));
    MessageBox.Show("Total Controls: " + c.Count());
}

และจะส่งคืนการนับที่เหมาะสมทุกครั้งดังนั้นฉันคิดว่าสิ่งนี้จะทำงานได้อย่างสมบูรณ์แบบสำหรับสิ่งที่คุณกำลังมองหา :)


21
GetAll () ที่กำหนดไว้ที่นี่เป็นตัวเลือกที่ดีมากสำหรับวิธีการขยายไปยังคลาส Control
Michael Bahig

ฉันชอบวิธีที่คุณใช้นิพจน์แลมบ์ดา เรียนรู้นิพจน์แลมด้าอย่างละเอียดได้ที่ไหน?
Aditya Bokade

"System.Windows.Forms.Control.ControlCollection" ไม่มีคำจำกัดความสำหรับ "Cast" และไม่มีวิธีการขยาย "Cast" ที่ยอมรับอาร์กิวเมนต์แรกของประเภท 'System.Windows.Forms.Control.ControlCollection' (คือ คุณขาดคำสั่งโดยใช้หรือการอ้างอิงการประกอบหรือไม่) "ฉันใช้. NET 4.5 และ" Controls "ไม่มีฟังก์ชัน / วิธีการ" Cast "/ อะไรก็ตาม ฉันขาดอะไรไป?
soulblazer

2
@soulblazer เพิ่ม System.Linq namespace
Ivan-Mark Debono

var allCtl = GetAll (this.FindForm (), typeof (TextBox)); // นี่คือ Usercontrol ส่งคืน Nothing !!
bh_earth0

34

ใน C # (เนื่องจากคุณติดแท็กไว้เช่นนี้) คุณสามารถใช้นิพจน์ LINQ ดังนี้:

List<Control> c = Controls.OfType<TextBox>().Cast<Control>().ToList();

แก้ไขสำหรับการเรียกซ้ำ:

ในตัวอย่างนี้คุณต้องสร้างรายการตัวควบคุมก่อนแล้วจึงเรียกใช้วิธีการเพื่อเติมข้อมูล เนื่องจากวิธีนี้เป็นแบบวนซ้ำจึงไม่ส่งคืนรายการ แต่เพียงแค่อัปเดต

List<Control> ControlList = new List<Control>();
private void GetAllControls(Control container)
{
    foreach (Control c in container.Controls)
    {
        GetAllControls(c);
        if (c is TextBox) ControlList.Add(c);
    }
}

อาจเป็นไปได้ที่จะทำสิ่งนี้ในคำสั่ง LINQ โดยใช้Descendantsฟังก์ชันนี้แม้ว่าฉันจะไม่คุ้นเคยกับมัน ดูหน้านี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนั้น

แก้ไข 2 เพื่อส่งคืนคอลเล็กชัน:

ตามที่ @ProfK แนะนำวิธีที่ส่งคืนการควบคุมที่ต้องการก็น่าจะเป็นแนวทางปฏิบัติที่ดีกว่า เพื่อแสดงให้เห็นสิ่งนี้ฉันได้แก้ไขโค้ดดังนี้:

private IEnumerable<Control> GetAllTextBoxControls(Control container)
{
    List<Control> controlList = new List<Control>();
    foreach (Control c in container.Controls)
    {
        controlList.AddRange(GetAllTextBoxControls(c));
        if (c is TextBox)
            controlList.Add(c);
    }
    return controlList;
}

ขอบคุณ C # หรือ VB ก็ดีสำหรับฉัน แต่ปัญหาคือ Controls.OfType <TExtbox> จะส่งกลับเฉพาะชายด์ของตัวควบคุมปัจจุบันเท่านั้น (ในกรณีของฉันคือ Form) และฉันต้องการในการเรียกเพียงครั้งเดียวเพื่อรับคอนโทรลทั้งหมดใน Forma "เรียกซ้ำ" (chiilds, sub-childs , sub-sub-childs, ..... ) ใน asingle collection.
ลุย

ฉันคาดว่าเมธอดที่เรียกว่า GetAllControls จะส่งคืนคอลเล็กชันการควบคุมซึ่งฉันจะกำหนดให้กับ ControlList ดูเหมือนว่าการปฏิบัติที่ดีขึ้น
ProfK

@ProfK ฉันเห็นด้วยกับคุณ เปลี่ยนตัวอย่างตาม
JYelton

13

นี่คือ GetAllControls () แบบเรียกซ้ำที่ได้รับการปรับปรุงซึ่งใช้งานได้จริงกับตัวแปรส่วนตัว:

    private void Test()
    {
         List<Control> allTextboxes = GetAllControls(this);
    }
    private List<Control> GetAllControls(Control container, List<Control> list)
    {
        foreach (Control c in container.Controls)
        {
            if (c is TextBox) list.Add(c);
            if (c.Controls.Count > 0)
                list = GetAllControls(c, list);
        }

        return list;
    }
    private List<Control> GetAllControls(Control container)
    {
        return GetAllControls(container, new List<Control>());
    }

10

ฉันรวมแนวคิดก่อนหน้านี้ไว้ในวิธีการขยายวิธีเดียว OfType()ประโยชน์ที่นี่มีให้คุณได้รับพิมพ์อย่างถูกต้องกลับไปนับรวมทั้งการถ่ายทอดทางพันธุกรรมจะถูกจัดการอย่างถูกต้องโดย

public static IEnumerable<T> FindAllChildrenByType<T>(this Control control)
{
    IEnumerable<Control> controls = control.Controls.Cast<Control>();
    return controls
        .OfType<T>()
        .Concat<T>(controls.SelectMany<Control, T>(ctrl => FindAllChildrenByType<T>(ctrl)));
}

5

คุณสามารถใช้แบบสอบถาม LINQ เพื่อดำเนินการนี้ สิ่งนี้จะสอบถามทุกอย่างในแบบฟอร์มที่เป็น TextBox

var c = from controls in this.Controls.OfType<TextBox>()
              select controls;

ขอบคุณ แต่ปัญหาเดียวกันกับคำตอบของเธอมันส่งคืนเฉพาะ chidls แต่ไม่ใช่ subchilds ฯลฯ และฉันต้องการการควบคุมทั้งหมด ฉันแน่ใจว่าสวยผมเห็นว่ามันเป็น posible ด้วยการเรียกวิธีการเดียวที่เป็นของใหม่ใน NET 3.5 หรือ 4.0 จำได้ว่าผมเห็นว่าใน somewehre สาธิต
หลุยส์

การเพิกเฉยต่อการขาดการเรียกซ้ำจะไม่var c = this.Controls.OfType<TextBox>()ให้ผลลัพธ์เหมือนกันหรือ?
CoderDennis

2
@ เดนนิส: ใช่มันเป็นเรื่องของความชอบ (โดยปกติ) ดูstackoverflow.com/questions/214500/…สำหรับการสนทนาที่น่าสนใจในเรื่องนี้
JYelton

5

อาจเป็นเทคนิคโบราณ แต่ใช้งานได้เหมือนมีเสน่ห์ ฉันใช้การเรียกซ้ำเพื่อเปลี่ยนสีของป้ายกำกับทั้งหมดของตัวควบคุม มันใช้งานได้ดี

internal static void changeControlColour(Control f, Color color)
{
    foreach (Control c in f.Controls)
    {

        // MessageBox.Show(c.GetType().ToString());
        if (c.HasChildren)
        {
            changeControlColour(c, color);
        }
        else
            if (c is Label)
            {
                Label lll = (Label)c;
                lll.ForeColor = color;
            }
    }
}

4

ฉันต้องการแก้ไขคำตอบของ PsychoCoders: เนื่องจากผู้ใช้ต้องการได้รับการควบคุมทั้งหมดในบางประเภทเราสามารถใช้ generics ได้ด้วยวิธีต่อไปนี้:

    public IEnumerable<T> FindControls<T>(Control control) where T : Control
    {
        // we can't cast here because some controls in here will most likely not be <T>
        var controls = control.Controls.Cast<Control>();

        return controls.SelectMany(ctrl => FindControls<T>(ctrl))
                                  .Concat(controls)
                                  .Where(c => c.GetType() == typeof(T)).Cast<T>();
    }

ด้วยวิธีนี้เราสามารถเรียกใช้ฟังก์ชันได้ดังนี้:

private void Form1_Load(object sender, EventArgs e)
{
    var c = FindControls<TextBox>(this);
    MessageBox.Show("Total Controls: " + c.Count());
}

นี่เป็นวิธีแก้ปัญหาที่ดีที่สุด (และเร็วที่สุดตามการทดสอบของฉัน) ในความคิดของฉันในหน้านี้ แต่ฉันขอแนะนำให้คุณเปลี่ยนการควบคุมเป็นอาร์เรย์: var enumerable = controls as Control [] ?? controls.ToArray (); จากนั้นเปลี่ยนเป็น: return enumerable.SelectMany (FindControls <T>) .Concat (enumerable) Where (c => c.GetType () == typeof (T)) Cast <T> ();
Randall Flagg

การใช้.OfType<T>()วิธี Linq ไม่มีประสิทธิภาพมากกว่า.Where(c => c.GetType() == typeof(T)).Cast<T>();เพื่อให้ได้ผลเช่นเดียวกันหรือไม่?
TheHitchenator

3

อย่าลืมว่าคุณสามารถมีกล่องข้อความอยู่ในส่วนควบคุมอื่น ๆ นอกเหนือจากตัวควบคุมคอนเทนเนอร์ได้เช่นกัน คุณยังสามารถเพิ่มกล่องข้อความลงใน PictureBox

ดังนั้นคุณต้องตรวจสอบด้วยว่า

someControl.HasChildren = True

ในฟังก์ชันเรียกซ้ำใด ๆ

นี่คือผลลัพธ์ที่ฉันได้จากเค้าโครงเพื่อทดสอบโค้ดนี้:

TextBox13   Parent = Panel5
TextBox12   Parent = Panel5
TextBox9   Parent = Panel2
TextBox8   Parent = Panel2
TextBox16   Parent = Panel6
TextBox15   Parent = Panel6
TextBox14   Parent = Panel6
TextBox10   Parent = Panel3
TextBox11   Parent = Panel4
TextBox7   Parent = Panel1
TextBox6   Parent = Panel1
TextBox5   Parent = Panel1
TextBox4   Parent = Form1
TextBox3   Parent = Form1
TextBox2   Parent = Form1
TextBox1   Parent = Form1
tbTest   Parent = myPicBox

ลองใช้ปุ่มเดียวและRichTextBox หนึ่งรายการในแบบฟอร์ม

Option Strict On
Option Explicit On
Option Infer Off

Public Class Form1

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

        Dim pb As New PictureBox
        pb.Name = "myPicBox"
        pb.BackColor = Color.Goldenrod
        pb.Size = New Size(100, 100)
        pb.Location = New Point(0, 0)
        Dim tb As New TextBox
        tb.Name = "tbTest"
        pb.Controls.Add(tb)
        Me.Controls.Add(pb)

        Dim textBoxList As New List(Of Control)
        textBoxList = GetAllControls(Of TextBox)(Me)

        Dim sb As New System.Text.StringBuilder
        For index As Integer = 0 To textBoxList.Count - 1
            sb.Append(textBoxList.Item(index).Name & "   Parent = " & textBoxList.Item(index).Parent.Name & System.Environment.NewLine)
        Next

        RichTextBox1.Text = sb.ToString
    End Sub

    Private Function GetAllControls(Of T)(ByVal searchWithin As Control) As List(Of Control)

        Dim returnList As New List(Of Control)

        If searchWithin.HasChildren = True Then
            For Each ctrl As Control In searchWithin.Controls
                If TypeOf ctrl Is T Then
                    returnList.Add(ctrl)
                End If
                returnList.AddRange(GetAllControls(Of T)(ctrl))
            Next
        ElseIf searchWithin.HasChildren = False Then
            For Each ctrl As Control In searchWithin.Controls
                If TypeOf ctrl Is T Then
                    returnList.Add(ctrl)
                End If
                returnList.AddRange(GetAllControls(Of T)(ctrl))
            Next
        End If
        Return returnList
    End Function

End Class

2

ใช้การสะท้อน:

// Return a list with all the private fields with the same type
List<T> GetAllControlsWithTypeFromControl<T>(Control parentControl)
{
    List<T> retValue = new List<T>();
    System.Reflection.FieldInfo[] fields = parentControl.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    foreach (System.Reflection.FieldInfo field in fields)
    {
      if (field.FieldType == typeof(T))
        retValue.Add((T)field.GetValue(parentControl));
    }
}

List<TextBox> ctrls = GetAllControlsWithTypeFromControl<TextBox>(this);

2

นี่คือวิธีการขยายของฉันสำหรับControlโดยใช้ LINQ เป็นการปรับรุ่น@PsychoCoder :

ใช้รายการประเภทแทนซึ่งช่วยให้คุณไม่ต้องโทรหลายครั้งGetAllเพื่อให้ได้สิ่งที่คุณต้องการ ปัจจุบันฉันใช้มันเป็นเวอร์ชันโอเวอร์โหลด

public static IEnumerable<Control> GetAll(this Control control, IEnumerable<Type> filteringTypes)
{
    var ctrls = control.Controls.Cast<Control>();

    return ctrls.SelectMany(ctrl => GetAll(ctrl, filteringTypes))
                .Concat(ctrls)
                .Where(ctl => filteringTypes.Any(t => ctl.GetType() == t));
}

การใช้งาน:

//   The types you want to select
var typeToBeSelected = new List<Type>
{
    typeof(TextBox)
    , typeof(MaskedTextBox)
    , typeof(Button)
};

//    Only one call
var allControls = MyControlThatContainsOtherControls.GetAll(typeToBeSelected);

//    Do something with it
foreach(var ctrl in allControls)
{
    ctrl.Enabled = true;
}

2

วิธีแก้ปัญหาที่ง่ายและสะอาด (C #):

static class Utilities {
    public static List<T> GetAllControls<T>(this Control container) where T : Control {
        List<T> controls = new List<T>();
        if (container.Controls.Count > 0) {
            controls.AddRange(container.Controls.OfType<T>());
            foreach (Control c in container.Controls) {
                controls.AddRange(c.GetAllControls<T>());
            }
        }

        return controls;
    }
}

รับกล่องข้อความทั้งหมด:

List<TextBox> textboxes = myControl.GetAllControls<TextBox>();

2

คุณสามารถใช้รหัสด้านล่างนี้

public static class ExtensionMethods
{
    public static IEnumerable<T> GetAll<T>(this Control control)
    {
        var controls = control.Controls.Cast<Control>();

        return controls.SelectMany(ctrl => ctrl.GetAll<T>())
                                  .Concat(controls.OfType<T>());
    }
}

2

นี่คือวิธีการขยายของฉัน มีประสิทธิภาพมากและขี้เกียจ

การใช้งาน:

var checkBoxes = tableLayoutPanel1.FindChildControlsOfType<CheckBox>();

foreach (var checkBox in checkBoxes)
{
    checkBox.Checked = false;
}

รหัสคือ:

public static IEnumerable<TControl> FindChildControlsOfType<TControl>(this Control control) where TControl : Control
    {
        foreach (var childControl in control.Controls.Cast<Control>())
        {
            if (childControl.GetType() == typeof(TControl))
            {
                yield return (TControl)childControl;
            }
            else
            {
                foreach (var next in FindChildControlsOfType<TControl>(childControl))
                {
                    yield return next;
                }
            }
        }
    }

นี่เป็นเวอร์ชันที่สะอาดกว่าซึ่งขี้เกียจสามารถแจกแจงและดึงข้อมูลได้ตามต้องการ
Jone Polvora


1
public List<Control> GetAllChildControls(Control Root, Type FilterType = null)
{
    List<Control> AllChilds = new List<Control>();
    foreach (Control ctl in Root.Controls) {
        if (FilterType != null) {
            if (ctl.GetType == FilterType) {
                AllChilds.Add(ctl);
            }
        } else {
            AllChilds.Add(ctl);
        }
        if (ctl.HasChildren) {
            GetAllChildControls(ctl, FilterType);
        }
    }
    return AllChilds;
}

1
   IEnumerable<Control> Ctrls = from Control ctrl in Me.Controls where ctrl is TextBox | ctrl is GroupBox select ctr;

แลมบ์ดานิพจน์

IEnumerable<Control> Ctrls = Me.Controls.Cast<Control>().Where(c => c is Button | c is GroupBox);

โปรดเพิ่มเติมในคำตอบของคุณที่อธิบายถึงสิ่งที่เกิดขึ้นและเกี่ยวข้องกับคำถามอย่างไร
Fencer04

0

ฉันแก้ไขจาก @PsychoCoder ตอนนี้สามารถพบการควบคุมทั้งหมดได้แล้ว

public static IEnumerable<T> GetChildrens<T>(Control control)
{
  var type = typeof (T);

  var allControls = GetAllChildrens(control);

  return allControls.Where(c => c.GetType() == type).Cast<T>();
}

private static IEnumerable<Control> GetAllChildrens(Control control)
{
  var controls = control.Controls.Cast<Control>();
  return controls.SelectMany(c => GetAllChildrens(c))
    .Concat(controls);
}

0

สิ่งนี้อาจใช้ได้:

Public Function getControls(Of T)() As List(Of T)
    Dim st As New Stack(Of Control)
    Dim ctl As Control
    Dim li As New List(Of T)

    st.Push(Me)

    While st.Count > 0
        ctl = st.Pop
        For Each c In ctl.Controls
            st.Push(CType(c, Control))
            If c.GetType Is GetType(T) Then
                li.Add(CType(c, T))
            End If
        Next
    End While

    Return li
End Function

ผมคิดว่าฟังก์ชั่นที่จะได้รับการควบคุมสิ่งที่คุณกำลังพูดถึงจะใช้ได้เฉพาะกับWPF


0

นี่คือโซลูชันทั่วไปที่ผ่านการทดสอบและใช้งานได้:

ฉันมีตัวควบคุม UpDownNumeric จำนวนมากบางตัวอยู่ในรูปแบบหลักบางตัวอยู่ใน groupboxes ภายในฟอร์ม ฉันต้องการเพียงตัวควบคุมที่เลือกสุดท้ายเพื่อเปลี่ยนสีกลับเป็นสีเขียวซึ่งฉันตั้งค่าอื่น ๆ ทั้งหมดเป็นสีขาวก่อนโดยใช้วิธีนี้: (ยังสามารถขยายเป็นรุ่นหลานได้)

    public void setAllUpDnBackColorWhite()
    {
        //To set the numericUpDown background color of the selected control to white: 
        //and then the last selected control will change to green.

        foreach (Control cont in this.Controls)
        {
           if (cont.HasChildren)
            {
                foreach (Control contChild in cont.Controls)
                    if (contChild.GetType() == typeof(NumericUpDown))
                        contChild.BackColor = Color.White;
            }
            if (cont.GetType() == typeof(NumericUpDown))
                cont.BackColor = Color.White;
       }
    }   

วิธีนี้จะไม่ได้ผลหากการควบคุมเด็กมีลูกของตัวเอง
soulblazer

0

คุณสามารถลองสิ่งนี้ได้หากต้องการ :)

    private void ClearControls(Control.ControlCollection c)
    {
        foreach (Control control in c)
        {
            if (control.HasChildren)
            {
                ClearControls(control.Controls);
            }
            else
            {
                if (control is TextBox)
                {
                    TextBox txt = (TextBox)control;
                    txt.Clear();
                }
                if (control is ComboBox)
                {
                    ComboBox cmb = (ComboBox)control;
                    if (cmb.Items.Count > 0)
                        cmb.SelectedIndex = -1;
                }

                if (control is CheckBox)
                {
                    CheckBox chk = (CheckBox)control;
                    chk.Checked = false;
                }

                if (control is RadioButton)
                {
                    RadioButton rdo = (RadioButton)control;
                    rdo.Checked = false;
                }

                if (control is ListBox)
                {
                    ListBox listBox = (ListBox)control;
                    listBox.ClearSelected();
                }
            }
        }
    }
    private void btnClear_Click(object sender, EventArgs e)
    {
        ClearControls((ControlCollection)this.Controls);
    }

1
การโพสต์โค้ดเพียงเล็กน้อยก็ช่วยให้ OP เข้าใจปัญหาหรือวิธีแก้ปัญหาของคุณได้เล็กน้อย คุณควรใส่คำอธิบายบางอย่างไว้พร้อมกับรหัสของคุณเสมอ
leigero

คำถามไม่ได้บอกอะไรเกี่ยวกับการล้างแบบฟอร์ม
LarsTech

ใช่ไม่ได้ตอบ "คำถาม" แต่เป็นส่วนเสริมที่ดี ขอบคุณ!

0

แม้ว่าผู้ใช้รายอื่นหลายคนจะโพสต์วิธีแก้ปัญหาไว้เพียงพอแล้ว แต่ฉันก็อยากจะโพสต์วิธีการทั่วไปที่อาจเป็นประโยชน์มากกว่า

นี่ขึ้นอยู่กับการตอบสนองของ JYelton เป็นส่วนใหญ่

public static IEnumerable<Control> AllControls(
    this Control control, 
    Func<Control, Boolean> filter = null) 
{
    if (control == null)
        throw new ArgumentNullException("control");
    if (filter == null)
        filter = (c => true);

    var list = new List<Control>();

    foreach (Control c in control.Controls) {
        list.AddRange(AllControls(c, filter));
        if (filter(c))
            list.Add(c);
    }
    return list;
}

0
    public static IEnumerable<T> GetAllControls<T>(this Control control) where T : Control
    {
        foreach (Control c in control.Controls)
        {
            if (c is T)
                yield return (T)c;
            foreach (T c1 in c.GetAllControls<T>())
                yield return c1;
        }
    }

0
    public IEnumerable<T> GetAll<T>(Control control) where T : Control
    {
        var type = typeof(T);
        var controls = control.Controls.Cast<Control>().ToArray();
        foreach (var c in controls.SelectMany(GetAll<T>).Concat(controls))
            if (c.GetType() == type) yield return (T)c;
    }

0

สำหรับใครก็ตามที่กำลังมองหาโค้ด C # ของ Adam รุ่น VB ที่เขียนเป็นส่วนขยายของControlคลาส:

''' <summary>Collects child controls of the specified type or base type within the passed control.</summary>
''' <typeparam name="T">The type of child controls to include. Restricted to objects of type Control.</typeparam>
''' <param name="Parent">Required. The parent form control.</param>
''' <returns>An object of type IEnumerable(Of T) containing the control collection.</returns>
''' <remarks>This method recursively calls itself passing child controls as the parent control.</remarks>
<Extension()>
Public Function [GetControls](Of T As Control)(
    ByVal Parent As Control) As IEnumerable(Of T)

    Dim oControls As IEnumerable(Of Control) = Parent.Controls.Cast(Of Control)()
    Return oControls.SelectMany(Function(c) GetControls(Of T)(c)).Concat(oControls.Where(Function(c) c.GetType() Is GetType(T) Or c.GetType().BaseType Is GetType(T))
End Function

หมายเหตุ: ฉันได้เพิ่มไฟล์ BaseTypeจับคู่สำหรับการควบคุมแบบกำหนดเองที่ได้รับมา คุณสามารถลบสิ่งนี้ออกหรือทำให้เป็นพารามิเตอร์ก็ได้หากต้องการ

การใช้

Dim oButtons As IEnumerable(Of Button) = Me.GetControls(Of Button)()

0

สร้างวิธีการ

public static IEnumerable<Control> GetControlsOfType<T>(Control control)
{
    var controls = control.Controls.Cast<Control>();
    return controls.SelectMany(ctrl => GetControlsOfType<T>(ctrl)).Concat(controls).Where(c => c is T);
}

และใช้มัน Like

Var controls= GetControlsOfType<TextBox>(this);//You can replace this with your control

0

ฉันกำลังใช้ VB ดังนั้นฉันจึงเขียนวิธีการขยาย ที่ดึงข้อมูลย่อยทั้งหมดและย่อยของการควบคุม

Imports System.Runtime.CompilerServices
Module ControlExt

<Extension()>
Public Function GetAllChildren(Of T As Control)(parentControl As Control) As IEnumerable(Of T)
    Dim controls = parentControl.Controls.Cast(Of Control)
    Return controls.SelectMany(Of Control)(Function(ctrl) _
        GetAllChildren(Of T)(ctrl)) _
        .Concat(controls) _
        .Where(Function(ctrl) ctrl.GetType() = GetType(T)) _
    .Cast(Of T)
End Function

End Module

จากนั้นคุณสามารถใช้มันโดยที่ "btnList" เป็นตัวควบคุม

btnList.GetAllChildren(Of HtmlInputRadioButton).FirstOrDefault(Function(rb) rb.Checked)

ในกรณีนี้จะเป็นการเลือกปุ่มตัวเลือกที่เลือก


-1

เพียง:

For Each ctrl In Me.Controls.OfType(Of Button)()
   ctrl.Text = "Hello World!"
Next

การดำเนินการนี้จะพบเฉพาะการควบคุมโดยตรงในคอลเล็กชันการควบคุมของ "ฉัน" และไม่พบปุ่มควบคุมที่อยู่ในคอนเทนเนอร์ย่อยใด ๆ เนื่องจากผู้โพสต์พยายามบอกเป็นนัยโดย "ทั้งหมด"
ChrisPBacon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.