wckdspn
Topic Author
Posts: 67
Joined: 18 Aug 2012, 23:14

Best way to get child in usercontrol content template

20 Feb 2014, 23:22

So, say I have a user control like this:
<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>
Which is used in XAML like this:
	<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>
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:
			var topbar = window.GetTemplateChild("TopBar").As<Rectangle>();
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.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Best way to get child in usercontrol content template

20 Feb 2014, 23:57

Hi,

Elements defined in the Logical Tree are registered against the root NameScope, so to find the "Foo" element do the following:
var foo = root.FindName<Button>("Foo");
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>.
 
wckdspn
Topic Author
Posts: 67
Joined: 18 Aug 2012, 23:14

Re: Best way to get child in usercontrol content template

21 Feb 2014, 01:21

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.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Best way to get child in usercontrol content template

22 Feb 2014, 02:15

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:
<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>
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
[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); }
    }
}
WindowControl.xaml
<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>
Test.xaml
<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>

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Semrush [Bot] and 21 guests