当网格在 DataTemplate 中时如何设置网格的可见性?

How to set the visiblility of a grid when the grid is inside a DataTemplate?

在我们的 UWP 应用程序中,MyListView 的 DataTemplate 在后面的代码中设置为 Page.Resources 中的 DataTemplateA 或 DataTemplateB。每个数据模板包含一个网格 (TopGrid),其中包含一个 DisplayGridButton 和另一个网格 (DisplayGrid)。

DisplayGrid 包含 SecondListView 和一个 HideGridButton

DisplayGridButton 应该显示 DisplayGrid。 HideGridButton 应该折叠 DisplayGrid。

XAML是

<Page.Resources>
    <DataTemplate x:Key="DataTemplateA">
        <Grid Name="TopGrid">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal">
                <TextBox/>
                <Button Name="DisplayGridButton" Content="Show" Margin="10,0" Click="DisplayGridButton_Click"/>
            </StackPanel>
            <Grid Name="DisplayGrid" Grid.Row="1" Visibility="Collapsed">
                <StackPanel>
                    <Button Name="HideGridButton" Content="Hide" Click="HideGridButton_Click"/>
                    <ListView Name="SecondListView">
                        <ListView.ItemTemplate>
                            <DataTemplate >

                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </StackPanel>
            </Grid>
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="DataTemplateB">
        <Grid Name="TopGrid">
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <StackPanel Orientation="Horizontal">
                <TextBox/>
                <Button Name="DisplayGridButton" Content="Show" Margin="10,0" Click="DisplayGridButton_Click"/>
            </StackPanel>
            <Grid Name="DisplayGrid" Grid.Row="1" Visibility="Collapsed">
                <StackPanel>
                    <Button Name="HideGridButton" Content="Hide" Click="HideGridButton_Click"/>
                    <ListView Name="SecondListView">
                        <ListView.ItemTemplate>
                            <DataTemplate >

                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </StackPanel>
            </Grid>
        </Grid>
    </DataTemplate>
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView Name="MyListView">

    </ListView>
</Grid>

在后面的代码中设置了DataTemplateA或DataTemplateB。

if (condition)
{
    MyListView.ItemTemplate = (DataTemplate)Resources["DataTemplateA"];
}
    else
{
    MyListView.ItemTemplate = (DataTemplate)Resources["DataTemplateB"];
}

在后面的代码中,我可以创建事件处理程序,但无法访问 DisplayGrid 以使其可见或折叠。

我通常会这样设置可见性。

 private void DisplayGridButton_Click(object sender, RoutedEventArgs e)
    {
        DisplayGrid.Visibility = Visibility.Visible;
    }

 private void HideGridButton_Click(object sender, RoutedEventArgs e)
    {
        DisplayGrid.Visibility = Visibility.Collapsed;
    }

如何从按钮单击事件访问 DataTemplate 中的 DisplayGrid?

由于网格是在模板中定义的,因此您必须在运行时将其挖掘出来。 (如果您可以从代码隐藏中将其引用为 "DisplayGrid",您无论如何都不知道它属于哪个列表视图项。)

像这样实现点击处理程序:

private void DisplayGridButton_Click(object sender, RoutedEventArgs e)
{
    Button button = sender as Button;
    StackPanel stackPanel = button?.Parent as StackPanel;
    Grid grid = stackPanel?.Parent as Grid;
    if (grid != null)
    {
        Grid displayGrid = FindVisualChild<Grid>(grid, "DisplayGrid");
        if (displayGrid != null)
        {
            displayGrid.Visibility = Visibility.Visible;
        }
    }
}

private void HideGridButton_Click(object sender, RoutedEventArgs e)
{
    Button button = sender as Button;
    StackPanel stackPanel = button?.Parent as StackPanel;
    Grid grid = stackPanel?.Parent as Grid;
    if (grid != null)
    {
        grid.Visibility = Visibility.Collapsed;
    }
}

(公平警告:此代码找到合适的父级的方式有点脆弱;如果模板更改,它可能会中断。按名称搜索会更好,但我现在没有任何方便的东西.)

这是在可视化树中查找命名子项的辅助方法:

public static T FindVisualChild<T>(
    DependencyObject parent,
    string name = null)
    where T : DependencyObject
{
    if (parent != null)
    {
        int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < childrenCount; i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(parent, i);
            T candidate = child as T;
            if (candidate != null)
            {
                if (name == null)
                {
                    return candidate;
                }

                FrameworkElement element = candidate as FrameworkElement;
                if (name == element?.Name)
                {
                    return candidate;
                }
            }

            T childOfChild = FindVisualChild<T>(child, name);
            if (childOfChild != null)
            {
                return childOfChild;
            }
        }
    }

    return default(T);
}

(此方法也可以只按类型搜索;只需将 null 作为名称传递即可。)