In our UWP app the DataTemplate for MyListView is set in the code behind to either DataTemplateA or DataTemplateB in Page.Resources. Each data template contains a grid (TopGrid) which contains a DisplayGridButton and another grid (DisplayGrid).
DisplayGrid contains SecondListView and a HideGridButton
DisplayGridButton should show DisplayGrid. HideGridButton should collapse DisplayGrid.
The XAML is
<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 or DataTemplateB is set in the code behind.
if (condition)
{
MyListView.ItemTemplate = (DataTemplate)Resources["DataTemplateA"];
}
else
{
MyListView.ItemTemplate = (DataTemplate)Resources["DataTemplateB"];
}
In the Code behind I can create the event handler but I cannot access the DisplayGrid to make it visible or to collapse it.
I would normally set visibility like this.
private void DisplayGridButton_Click(object sender, RoutedEventArgs e)
{
DisplayGrid.Visibility = Visibility.Visible;
}
private void HideGridButton_Click(object sender, RoutedEventArgs e)
{
DisplayGrid.Visibility = Visibility.Collapsed;
}
How do I access the DisplayGrid in the DataTemplate from the button click events?
Since the grid is defined in a template, you'll have to dig it out at runtime. (If you could reference it as "DisplayGrid" from code-behind, you wouldn't know which listview item it belonged to anyway.)
Implement click handlers something like this:
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;
}
}
(Fair warning: The way this code finds the appropriate parent to start from is a bit brittle; it might break if the template changes. Searching by name would be better, but I don't have anything handy right now.)
Here is the helper method that finds a named child in the visual tree:
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);
}
(This method can also search by type only; just pass null
as the name.)