[C#] 특정 형식 (버튼 / 텍스트 상자)의 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);
    }
}

Descendants내가 익숙하지는 않지만 함수를 사용하여 하나의 LINQ 문에서이 작업을 수행 할 수 있습니다 . 이 페이지 보기 대한 자세한 내용 를 .

컬렉션을 반환하려면 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;
}


답변

이것은 실제로 private vars에서 작동하는 재귀 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;
            }
    }
}


답변

PsychoCoders 답변을 수정하고 싶습니다. 사용자가 특정 유형의 모든 컨트롤을 얻으려면 다음과 같은 방법으로 제네릭을 사용할 수 있습니다.

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