Best way to get child in usercontrol content template
So, say I have a user control like this:
Which is used in XAML like this:
Now, given "Root" as a control reference, I want to find Foo in the hierarchy.
I can find things like "TopBar" given "Window", by using:
But I can't determine how to get something in the Content inside of Window (defined in the second XAML).
Ultimately, my goal is to have a Window user control which allows me to properly place child content inside of the window. I can do this in WPF (using both UserControl templates, as well as, and perhaps more optimally, with custom controls), but the path in Noesis (Unity) is unclear.
Code: Select all
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="UI.WindowControl"
x:Name="UserControl"
d:DesignWidth="380" d:DesignHeight="300">
<UserControl.Style>
<Style TargetType="{x:Type UserControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserControl}" >
<Grid x:Name="Window" HorizontalAlignment="Center" VerticalAlignment="Center" Width="380" Height="300" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.25" ScaleY="1.25"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Border BorderBrush="#BD000000" BorderThickness="1" Margin="-2">
<DockPanel>
<Grid Height="24" DockPanel.Dock="Top">
<Rectangle x:Name="TopBar" Fill="#FF2584BE"/>
<Button x:Name="CloseButton" Content="X" HorizontalAlignment="Right" VerticalAlignment="Center" Width="22" Margin="0,0,5,0" Foreground="Black" Background="#FF4AAAE4" BorderBrush="{x:Null}" FontFamily="/BlendProject;component/Fonts/#Arial" FontSize="16" FontWeight="Bold" Height="22" Padding="3,0"/>
</Grid>
<Grid x:Name="grid_Body" DockPanel.Dock="Top" Background="White">
<ContentPresenter Margin="4" x:Name="ContentHost"/>
</Grid>
</DockPanel>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Style>
</UserControl>
Code: Select all
<Grid x:Name="Root">
<UI:WindowControl x:Name="Window" Margin="210,150">
<Grid Margin="0,-12,0,0" Height="286">
<Button x:Name="Foo" />
</Grid>
</UI:WindowControl>
</Grid>
I can find things like "TopBar" given "Window", by using:
Code: Select all
var topbar = window.GetTemplateChild("TopBar").As<Rectangle>();
Ultimately, my goal is to have a Window user control which allows me to properly place child content inside of the window. I can do this in WPF (using both UserControl templates, as well as, and perhaps more optimally, with custom controls), but the path in Noesis (Unity) is unclear.
-
-
sfernandez
Site Admin
- Posts: 2908
- Joined:
Re: Best way to get child in usercontrol content template
Hi,
Elements defined in the Logical Tree are registered against the root NameScope, so to find the "Foo" element do the following:
The GetTemplateChild() function is used to look for elements in the instanced Visual Tree of a Template, that is, any named element inside the <ControlTemplate>Visual_Tree</ControlTemplate>.
Elements defined in the Logical Tree are registered against the root NameScope, so to find the "Foo" element do the following:
Code: Select all
var foo = root.FindName<Button>("Foo");
Re: Best way to get child in usercontrol content template
But that's just it, it didn't find it. But, that seems to be consistent with WPF which doesn't allow you to name those content components defined by a content template. It'll give you an error during build if you try.
So, I tried making another UserControl defining the content of what would fit in the Window UserControl. This worked, as far as being able to find things in the tree, however the Control does not display. I can see the Window UserControl and interact with it, but not the UserControl that is its Content.
So, I tried making another UserControl defining the content of what would fit in the Window UserControl. This worked, as far as being able to find things in the tree, however the Control does not display. I can see the Window UserControl and interact with it, but not the UserControl that is its Content.
-
-
sfernandez
Site Admin
- Posts: 2908
- Joined:
Re: Best way to get child in usercontrol content template
I just realized that you are specifying contents of the UserControl via a ControlTemplate. And then overwriting its Content property when it is included in another xaml. Setting UserControl.Content is not allowed (we should have thrown an error message to notify this scenario, I'll add it for next release), because content is loaded from the xaml associated with the UserControl.
Maybe you should use a ContentControl instead:
Or if you are still interested in using a UserControl, then you can create a new DependencyProperty that will hold the contents of your control:
WindowControl.cs
WindowControl.xaml
Test.xaml
Maybe you should use a ContentControl instead:
Code: Select all
<Grid x:Name="Root">
<Grid.Resources>
<ControlTemplate x:Key="WindowControlTemplate" TargetType="{x:Type ContentControl}" >
<Grid x:Name="Window" HorizontalAlignment="Center" VerticalAlignment="Center" Width="380" Height="300" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.25" ScaleY="1.25"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Border BorderBrush="#BD000000" BorderThickness="1" Margin="-2">
<DockPanel>
<Grid Height="24" DockPanel.Dock="Top">
<Rectangle x:Name="TopBar" Fill="#FF2584BE"/>
<Button x:Name="CloseButton" Content="X" HorizontalAlignment="Right" VerticalAlignment="Center" Width="22" Margin="0,0,5,0" Foreground="Black" Background="#FF4AAAE4" BorderBrush="{x:Null}" FontFamily="/BlendProject;component/Fonts/#Arial" FontSize="16" FontWeight="Bold" Height="22" Padding="3,0"/>
</Grid>
<Grid x:Name="grid_Body" DockPanel.Dock="Top" Background="White">
<ContentPresenter Margin="4" x:Name="ContentHost"/>
</Grid>
</DockPanel>
</Border>
</Grid>
</ControlTemplate>
</Grid.Resources>
<ContentControl x:Name="Window" Margin="210,150" Template="{StaticResource WindowControlTemplate}">
<Grid Margin="0,-12,0,0" Height="286">
<Button x:Name="Foo" />
</Grid>
</ContentControl>
</Grid>
WindowControl.cs
Code: Select all
[Extended]
[UserControlSource("Assets/UI/WindowControl.xaml")]
class WindowControl : UserControl
{
public static Noesis.DependencyProperty ChildProperty = Noesis.DependencyProperty.Register(
"Child", typeof(Noesis.UIElement), typeof(WindowControl),
new Noesis.PropertyMetadata(null));
public Noesis.UIElement Child
{
get { return GetValue<Noesis.UIElement>(ChildProperty); }
set { SetValue<Noesis.UIElement>(ChildProperty, value); }
}
}
Code: Select all
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="UI.WindowControl"
x:Name="UserControl"
d:DesignWidth="380" d:DesignHeight="300">
<Grid x:Name="Window" HorizontalAlignment="Center" VerticalAlignment="Center" Width="380" Height="300" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.25" ScaleY="1.25"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<Border BorderBrush="#BD000000" BorderThickness="1" Margin="-2">
<DockPanel>
<Grid Height="24" DockPanel.Dock="Top">
<Rectangle x:Name="TopBar" Fill="#FF2584BE"/>
<Button x:Name="CloseButton" Content="X" HorizontalAlignment="Right" VerticalAlignment="Center" Width="22" Margin="0,0,5,0" Foreground="Black" Background="#FF4AAAE4" BorderBrush="{x:Null}" FontFamily="/BlendProject;component/Fonts/#Arial" FontSize="16" FontWeight="Bold" Height="22" Padding="3,0"/>
</Grid>
<Grid x:Name="grid_Body" DockPanel.Dock="Top" Background="White">
<ContentPresenter Margin="4" x:Name="ContentHost" Content="{Binding Child, ElementName=UserControl}"/>
</Grid>
</DockPanel>
</Border>
</Grid>
</UserControl>
Code: Select all
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UI="clr-namespace:UI">
<UI:WindowControl x:Name="Window" Margin="210,150">
<UI:WindowControl.Child>
<Grid>
<Button x:Name="Foo" />
</Grid>
</UI:WindowControl.Child>
</UI:WindowControl>
</Grid>