rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Button ControlTemplate Exception: Element is already loaded

08 Apr 2014, 23:38

Hey all, I'm slowly figuring out xaml and ran into an issue that I'm a bit stumped on. I've got a button control template that I wanted to add text drop shadow for, however I get the exception that the element is already loaded when I add a second ContentPresenter to the template, here's the code that works and below the code that doesn't. Any info would be greatly appreciated, and for reference I was following the info found here: http://mark-dot-net.blogspot.com/2007/0 ... te-in.html
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="GUIResources/ArtTextureAtlas.xaml"/>
                <ResourceDictionary Source="GUIResources/IconsTextureAtlas.xaml"/>
                <ResourceDictionary Source="GUIResources/InteractTextureAtlas.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <Style x:Key="ShadowStyle">
                <Setter Property="Control.Foreground" Value="LightGray" />
            </Style>

            <Style x:Key="InformButton" TargetType="Button">
                <Setter Property="OverridesDefaultStyle" Value="True"/>
                <Setter Property="Margin" Value="2"/>
                <Setter Property="FontFamily" Value="GUIFonts/#JandaAmazingGrace"/>
                <Setter Property="FontSize" Value="11px"/>
                <Setter Property="FontWeight" Value="Bold"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Border Name="Border" Background="{DynamicResource Btn_Cache_Internl_neutral}">
                                <Grid>
                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_over}" />
                                </Trigger>
                                <Trigger Property="IsPressed" Value="True">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_down}" />
                                    <Setter TargetName="content" Property="RenderTransform" >
                                        <Setter.Value>
                                            <TranslateTransform Y="1.0" />
                                        </Setter.Value>
                                    </Setter>
                                </Trigger>
                                <Trigger Property="IsDefaulted" Value="True">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_over}" />
                                </Trigger>
                                <Trigger Property="IsFocused" Value="True" />
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_inactive}" />
                                    <Setter Property="Foreground" Value="Gray" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Page.Resources>

    <StackPanel HorizontalAlignment="Center">
        <Button Style="{StaticResource InformButton}" Width="225" Height="63">Hello</Button>
        <Button Style="{StaticResource InformButton}">World</Button>
        <Button Style="{StaticResource InformButton}" FontSize="20">Big Button</Button>
        <Button Style="{StaticResource InformButton}" IsDefault="True">Default</Button>
        <Button Style="{StaticResource InformButton}" IsEnabled="False">Disabled</Button>
        <Button Style="{StaticResource InformButton}" Width="70" Height="30">70 x 30</Button>
        <TextBox />
        <Button Style="{StaticResource InformButton}" Width="30" Height="30">
            <Path Fill="Black" Data="M 3,3 l 9,9 l -9,9 Z" />
        </Button>
        <Button Width="70" Height="30">70 x 30</Button>
    </StackPanel>

</Page>
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:sys="clr-namespace:System;assembly=mscorlib" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Page.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="GUIResources/ArtTextureAtlas.xaml"/>
                <ResourceDictionary Source="GUIResources/IconsTextureAtlas.xaml"/>
                <ResourceDictionary Source="GUIResources/InteractTextureAtlas.xaml"/>
            </ResourceDictionary.MergedDictionaries>

            <Style x:Key="ShadowStyle">
                <Setter Property="Control.Foreground" Value="LightGray" />
            </Style>

            <Style x:Key="InformButton" TargetType="Button">
                <Setter Property="OverridesDefaultStyle" Value="True"/>
                <Setter Property="Margin" Value="2"/>
                <Setter Property="FontFamily" Value="GUIFonts/#JandaAmazingGrace"/>
                <Setter Property="FontSize" Value="11px"/>
                <Setter Property="FontWeight" Value="Bold"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Border Name="Border" Background="{DynamicResource Btn_Cache_Internl_neutral}">
                                <Grid>
                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="contentShadow" Style="{StaticResource ShadowStyle}">
                                        <ContentPresenter.RenderTransform>
                                            <TranslateTransform X="1.0" Y="1.0" />
                                        </ContentPresenter.RenderTransform>
                                    </ContentPresenter>
                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content"/>
                                </Grid>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_over}" />
                                </Trigger>
                                <Trigger Property="IsPressed" Value="True">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_down}" />
                                    <Setter TargetName="content" Property="RenderTransform" >
                                        <Setter.Value>
                                            <TranslateTransform Y="1.0" />
                                        </Setter.Value>
                                    </Setter>
                                </Trigger>
                                <Trigger Property="IsDefaulted" Value="True">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_over}" />
                                </Trigger>
                                <Trigger Property="IsFocused" Value="True" />
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter TargetName="Border" Property="Background" Value="{DynamicResource Btn_Cache_Internl_inactive}" />
                                    <Setter Property="Foreground" Value="Gray" />
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>
    </Page.Resources>

    <StackPanel HorizontalAlignment="Center">
        <Button Style="{StaticResource InformButton}" Width="225" Height="63">Hello</Button>
        <Button Style="{StaticResource InformButton}">World</Button>
        <Button Style="{StaticResource InformButton}" FontSize="20">Big Button</Button>
        <Button Style="{StaticResource InformButton}" IsDefault="True">Default</Button>
        <Button Style="{StaticResource InformButton}" IsEnabled="False">Disabled</Button>
        <Button Style="{StaticResource InformButton}" Width="70" Height="30">70 x 30</Button>
        <TextBox />
        <Button Style="{StaticResource InformButton}" Width="30" Height="30">
            <Path Fill="Black" Data="M 3,3 l 9,9 l -9,9 Z" />
        </Button>
        <Button Width="70" Height="30">70 x 30</Button>
    </StackPanel>

</Page>
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Button ControlTemplate Exception: Element is already loa

09 Apr 2014, 19:21

You can't have 2 ContentPresenter inside the same template because Content would be assigned to both, and a Visual element can only have 1 visual parent.

You have two options:

A) Use a binding to create the shadow TextBlock
B) Create the shadow text as part of the button content
<Grid
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid.Resources>
        <ControlTemplate x:Key="ButtonTemplate1" TargetType="Button">
            <Border Background="Silver" Padding="4,2">
                <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
                    <TextBlock Text="{TemplateBinding Content}" Foreground="White" Margin="1,1,-1,-1"/>
                    <ContentPresenter/>
                </Grid>
            </Border>
        </ControlTemplate>
        <ControlTemplate x:Key="ButtonTemplate2" TargetType="Button">
            <Border Background="Silver" Padding="4,2">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </Border>
        </ControlTemplate>
    </Grid.Resources>
    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button Content="This is a Button" Template="{StaticResource ButtonTemplate1}" Foreground="Black" Margin="2"/>
        <Button Template="{StaticResource ButtonTemplate2}" Margin="2">
            <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
                <TextBlock Text="{Binding Text, ElementName=txt}" Foreground="White" Margin="1,1,-1,-1"/>
                <TextBlock x:Name="txt" Text="This is a Button" Foreground="Black"/>
            </Grid>
        </Button>
    </StackPanel>
</Grid>
I think method A is more convenient, although it only works if you set Button.Content as a string.
 
rcalt2vt
Topic Author
Posts: 17
Joined: 21 Feb 2014, 22:59

Re: Button ControlTemplate Exception: Element is already loa

09 Apr 2014, 23:22

Awesome, that also answers a lot of other questions I had floating about on the whole template stuff. Though I can only assume that this works in Blend, but not NoesisGUI / Unity because of the WPF version I'm targeting or is this just one of those differences between WPF's implementation and Noesis' implementation?
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Button ControlTemplate Exception: Element is already loa

10 Apr 2014, 10:27

[An extension of my previous answer:]

I just realize you can even use 2 ContentPresenter in your template while the Button Content is a string:
<ControlTemplate x:Key="ButtonTemplate0" TargetType="Button">
    <Border Background="Silver" Padding="4,2">
        <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
            <ContentPresenter TextElement.Foreground="White" Margin="1,1,-1,-1"/>
            <ContentPresenter/>
        </Grid>
    </Border>
</ControlTemplate>
<Button
    Content="This is a Button"
    Template="{StaticResource ButtonTemplate0}"
    Foreground="Black"
    Margin="2"/>
You would get an error message only when Button Content is specified as any UI element (a TextBlock for example), because as I explained in the previous answer, a Visual can only have 1 Visual parent.
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Button ControlTemplate Exception: Element is already loa

10 Apr 2014, 17:06

Awesome, that also answers a lot of other questions I had floating about on the whole template stuff. Though I can only assume that this works in Blend, but not NoesisGUI / Unity because of the WPF version I'm targeting or is this just one of those differences between WPF's implementation and Noesis' implementation?
The behavior of NoesisGUI should be the same as in WPF/Blend, if that is not the case, we have a bug and we have to fix it.

I will make some tests and let you know.
 
wckdspn
Posts: 67
Joined: 18 Aug 2012, 23:14

Re: Button ControlTemplate Exception: Element is already loa

10 Apr 2014, 18:29

May be related to the templating issue in: viewtopic.php?f=3&t=316

Similar situation, in that it worked in Blend.
 
User avatar
sfernandez
Site Admin
Posts: 1911
Joined: 22 Dec 2011, 19:20

Re: Button ControlTemplate Exception: Element is already loa

11 Apr 2014, 02:11

Awesome, that also answers a lot of other questions I had floating about on the whole template stuff. Though I can only assume that this works in Blend, but not NoesisGUI / Unity because of the WPF version I'm targeting or is this just one of those differences between WPF's implementation and Noesis' implementation?
You were right, ContentPresenter was not behaving exactly the same in Blend and in NoesisGUI. I will fix the problem for the next release, so your xaml could load correctly.

Who is online

Users browsing this forum: No registered users and 1 guest