특정 유형(버튼/텍스트 상자)의 Windows Forms 양식에 대한 모든 하위 컨트롤을 가져오는 방법은 무엇입니까?
저는 x 유형의 양식에 대한 모든 제어를 받아야 합니다.나는 과거에 이런 코드를 한 번 본 적이 있다고 확신합니다.
dim ctrls() as Control
ctrls = Me.Controls(GetType(TextBox))
재귀적 기능을 사용하여 모든 제어를 반복할 수 있다는 것을 알고 있습니다. 하지만 다음과 같이 더 쉽고 간단한 방법이 있습니까?
Dim Ctrls = From ctrl In Me.Controls Where ctrl.GetType Is Textbox
여기 다른 옵션이 있습니다.샘플 애플리케이션을 만들어 테스트한 다음 GroupBox와 GroupBox를 초기 GroupBox 안에 넣었습니다.중첩된 GroupBox 안에 3개의 TextBox 컨트롤과 버튼을 넣었습니다.이것은 내가 사용한 코드입니다(심지어 당신이 찾던 재귀도 포함합니다).
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());
}
그리고 매번 적절한 카운트를 반환했기 때문에 이것은 당신이 찾고 있는 것에 완벽하게 작동할 것이라고 생각합니다 :)
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 문사하수있수습다니행할업을작다이서음에을나용"를 사용하여 한 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;
}
이것은 개인 변수에서 실제로 작동하는 재귀적 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>());
}
저는 이전의 아이디어들을 하나의 확장 방법으로 결합했습니다. 수 있는 하게 입력한 다시 수 있다는 은 정확하게 할 수 있다는 것입니다.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)));
}
LINQ 쿼리를 사용하여 이 작업을 수행할 수 있습니다.TextBox 유형의 양식에 있는 모든 항목을 쿼리합니다.
var c = from controls in this.Controls.OfType<TextBox>()
select controls;
고대의 기술일지도 모르지만, 그것은 매력적으로 작동합니다.컨트롤의 모든 레이블 색상을 변경하기 위해 재귀를 사용했습니다.잘 작동합니다.
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;
}
}
}
사이코코더스의 답변을 수정하고 싶습니다. 사용자가 특정 유형의 모든 제어를 원하기 때문에 제네릭을 다음과 같은 방식으로 사용할 수 있습니다.
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());
}
깨끗하고 간편한 솔루션(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>();
컨테이너 컨트롤 이외의 다른 컨트롤에도 TextBox가 있을 수 있습니다.텍스트 상자를 그림 상자에 추가할 수도 있습니다.
그래서 당신은 또한 확인할 필요가 있습니다.
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
양식에서 단추 하나와 리치 텍스트 상자 하나를 사용하여 사용해 보십시오.
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
아래 코드를 사용할 수 있습니다.
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>());
}
}
여기 내 확장 방법이 있습니다.그것은 매우 효율적이고 게으릅니다.
용도:
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;
}
}
}
}
반사 사용:
// 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);
다음은 제 확장 방법입니다.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;
}
여기에 해결책이 있습니다.
https://stackoverflow.com/a/19224936/1147352
나는 이 코드를 작성했고 패널만 선택했습니다. 당신은 그 안에 스위치나 if를 더 추가할 수 있습니다.
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;
}
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);
메서드 만들기
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);
}
그리고 사용하기 좋아요
Var controls= GetControlsOfType<TextBox>(this);//You can replace this with your control
저는 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)
이 경우 선택한 라디오 버튼이 선택됩니다.
@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);
}
이 방법은 다음과 같습니다.
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에서만 사용할 수 있다고 생각합니다.
다음은 테스트를 거쳐 작동하는 일반 솔루션입니다.
나는 많은 UpDownNumeric 컨트롤을 가지고 있는데, 일부는 기본 형식이고 일부는 양식 내 그룹 상자에 있습니다.다음 방법을 사용하여 마지막으로 선택한 컨트롤만 녹색으로 변경하고 다른 컨트롤은 모두 흰색으로 설정합니다. (손자로 확장할 수도 마찬가지입니다.
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;
}
}
당신이 원한다면 이것을 시도할 수 있습니다 :)
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);
}
몇몇 다른 사용자들이 적절한 솔루션을 게시했지만, 저는 더 유용할 수 있는 더 일반적인 접근 방식을 게시하고 싶습니다.
이것은 주로 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;
}
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;
}
}
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;
}
의 확장자로 작성된 Adam의 C# 코드의 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)()
Visual Basic VB.NET 230,000줄 이상의 코드를 c#에 이식하는 것을 거부하는 일부 사람들을 위해, 특정 유형만 필요하다면 필요에 따라 'where'를 추가하십시오.
Private Shared Function getAll(control As Control) As IEnumerable(Of Control)
Return control.Controls.Cast(Of Control) _
.SelectMany(Function(f) getAll(f).Concat(control.Controls.Cast(Of Control)))
End Function
단순:
For Each ctrl In Me.Controls.OfType(Of Button)()
ctrl.Text = "Hello World!"
Next
언급URL : https://stackoverflow.com/questions/3419159/how-to-get-all-child-controls-of-a-windows-forms-form-of-a-specific-type-button
'itsource' 카테고리의 다른 글
코드를 사용하여 WPF에서 메뉴 구분 기호 표시줄을 만드는 방법 (0) | 2023.05.22 |
---|---|
Reflection을 사용하여 개인 필드를 찾으시겠습니까? (0) | 2023.05.22 |
Python vs Bash - 성능 측면에서 각 작업이 다른 작업을 능가합니까? (0) | 2023.05.17 |
WPF 데이터 그리드에서 스크롤 막대를 활성화하려면 어떻게 해야 합니까? (0) | 2023.05.17 |
'_eq__'을(를) 정의하는 유형은 해시할 수 없습니까? (0) | 2023.05.17 |