Grabbing reference to element inside DataGridTempl

2019-07-29 13:01发布

I've been struggling with this problem for a while now and can't seem to get any answers on it. I've mocked up a simple XAML file to demonstrate the problem (I'm not providing my real XAML file since it has more in it than needed for this question).

Here is my question: given the following XAML file how can I get a reference in my codebehind to the selectHeight ComboBox that resides in the DataGridTemplateColumn.CellEditingTemplate DataTemplate? I need the reference so that I can change a property of the ComboBox based on a selection in the selectAge ComboBox.

<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
    <DataGrid Name="grdPeople"
                    AutoGenerateColumns="False"  
                    AlternatingRowBackground="LightBlue" 
                    CanUserAddRows="True" CanUserDeleteRows="True" IsEnabled="True"
                    MaxHeight="400" VerticalScrollBarVisibility="Auto">

        <DataGrid.Columns>
            <!--Name Column-->
            <DataGridTemplateColumn Header="MyName" CanUserReorder="False" CanUserResize="False"  CanUserSort="False" >
                <DataGridTemplateColumn.CellTemplate >
                    <DataTemplate>
                        <Label Content="{Binding Path=Name}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate >
                    <DataTemplate>
                        <TextBox Text="{Binding Path=Name}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>

            <!--Age Column-->
            <DataGridTemplateColumn Header="MyAge">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Label Content="{Binding Path=Age}"></Label>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox Name="selectAge" ItemsSource="{Binding Path=AgeOpts}">
                            <ComboBox.ItemTemplate>
                                <DataTemplate>
                                    <Label Content="{Binding Path=Age}"></Label>
                                </DataTemplate>
                            </ComboBox.ItemTemplate>    
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>

            <!--Height Column-->
            <DataGridTemplateColumn Header="MyHeight">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Label Content="{Binding Path=Height}"></Label>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>
                        <ComboBox Name="selectHeight" ItemsSource="{Binding Path=HeightOpts}">
                            <ComboBox.ItemTemplate>
                                <DataTemplate>
                                    <Label Content="{Binding Path=Height}"></Label>
                                </DataTemplate>
                            </ComboBox.ItemTemplate>
                        </ComboBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

I realize that what I'm trying to do may not be exactly "best practice" but I'm trying to work with what I've been given in legacy code.

I found this MSDN page relating to what I want to do but I can't figure out how to translate the example into my scenario: http://msdn.microsoft.com/en-us/library/system.windows.frameworktemplate.findname.aspx.

Any help would be appreciated! Thanks!

1条回答
女痞
2楼-- · 2019-07-29 13:31

Here's a library script I like using to navigate WPF's visual tree and find controls.

You use it like this: ComboBox cbx = FindChild<ComboBox>(grdPeople, "selectHeight");

It will return null if it can't find any ComboBox that is named "selectHeight" so be sure to check if cbx == null before using it.

public static T FindChild<T>(DependencyObject parent, string childName)
    where T : DependencyObject
{
    // Confirm parent and childName are valid. 
    if (parent == null) return null;

    T foundChild = null;

    int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < childrenCount; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        // If the child is not of the request child type child
        T childType = child as T;
        if (childType == null)
        {
            // recursively drill down the tree
            foundChild = FindChild<T>(child, childName);

            // If the child is found, break so we do not overwrite the found child. 
            if (foundChild != null) break;
        }
        else if (!string.IsNullOrEmpty(childName))
        {
            var frameworkElement = child as FrameworkElement;
            // If the child's name is set for search
            if (frameworkElement != null && frameworkElement.Name == childName)
            {
                // if the child's name is of the request name
                foundChild = (T)child;
                break;
            }
            else
            {
                // recursively drill down the tree
                foundChild = FindChild<T>(child, childName);

                // If the child is found, break so we do not overwrite the found child. 
                if (foundChild != null) break;
            }
        }
        else
        {
            // child element found.
            foundChild = (T)child;
            break;
        }
    }

    return foundChild;
}

public static T FindChild<T>(DependencyObject parent)
    where T : DependencyObject
{
    // Confirm parent is valid. 
    if (parent == null) return null;

    T foundChild = null;

    int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < childrenCount; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        // If the child is not of the request child type child
        T childType = child as T;
        if (childType == null)
        {
            // recursively drill down the tree
            foundChild = FindChild<T>(child);

            // If the child is found, break so we do not overwrite the found child. 
            if (foundChild != null) break;
        }
        else
        {
            // child element found.
            foundChild = (T)child;
            break;
        }
    }
    return foundChild;
}
查看更多
登录 后发表回答