Harjuna Dewabrata
Harjuna Dewabrata

Reputation: 31

List all controls of a specific window of WPF

I am very new to WPF and just would to ask your help for a very basic method of getting the Windows controls and their children as in Winform app. Bottom line is to have reusable code for multiple window/pages in a different different class.

Bunches of thanks before.

Public Sub GetControl(Wn As Window)
    For Each Ctrl As Control In Wn.Controls
        'Code here

        If Ctrl.HasChildren = True Then
            'Code here
        End If
    Next
End Sub

Upvotes: 2

Views: 4372

Answers (1)

Michael Puckett II
Michael Puckett II

Reputation: 6749

So here's the down low. You need to look for UIElement, which is a base class for all UIElements in XAML. There are two main types that host controls. ContentControl and Panel.
A ContentControl has a 'Content' property that is potentially containing an object. A Panel has a collection of UIElements property 'Children' and of type UIElement.

If you're looking just for the elements of a Window or ANY UIElement then you need to recursively search and make that list based on that information.

A Window inherits from ContentControl but that Content might be a Grid or StackPanel or any Panel or sorts and may have Children of UIElement also.

You cycle through them all until you get the results.

public MainWindow()
{
        InitializeComponent();

        foreach (var element in GetAllElementsFrom(this))
            Debug.WriteLine(element.ToString());
}

private IEnumerable<UIElement> GetAllElementsFrom(UIElement element)
{
    var uiElements = GetSingleElement();

       switch (element)
       {
            case Panel panel:
                foreach (var child in panel.Children)
                    uiElements = uiElements.Concat(GetInnerElements(child));
                break;
            case UserControl userControl:
                uiElements = uiElements.Concat(GetInnerElements(userControl.Content));
                break;
            case ContentControl contentControl:
                if (contentControl.Content is UIElement uiElement)
                    uiElements = uiElements.Concat(GetInnerElements(uiElement));
                break;
        }

    return uiElements;

    IEnumerable<UIElement> GetSingleElement()
    {
        yield return element;
    }
}

Here's the XAML I used.

<Grid>
    <Button>
        <DockPanel>
            <ContentControl>
                <Grid>
                    <TextBox />
                </Grid>
            </ContentControl>
        </DockPanel>
    </Button>

    <StackPanel>
        <Label />
        <TextBlock>
            Hey There!!
        </TextBlock>
        <Grid>
            <Ellipse />
        </Grid>
    </StackPanel>
</Grid>

And here's the result I got in my debug window:

System.Windows.Controls.Grid
System.Windows.Controls.Button
System.Windows.Controls.DockPanel
System.Windows.Controls.ContentControl
System.Windows.Controls.Grid
System.Windows.Controls.TextBox
System.Windows.Controls.StackPanel
System.Windows.Controls.Label
System.Windows.Controls.TextBlock
System.Windows.Controls.Grid
System.Windows.Shapes.Ellipse

Happy Coding! Note: Uses C# 7 syntax; if you're not on C# 7 then just make the changes, I think they're straight forward.

Upvotes: 2

Related Questions