Powered by MSDN

US - English
NEW! Silverlight 5 is available Learn More

Setting Button Template in Code-Behind RSS

7 replies

Last post Sep 18, 2008 09:38 PM by elBradford

(0)
  • elBradford

    elBradford

    Member

    6 Points

    9 Posts

    Setting Button Template in Code-Behind

    Sep 16, 2008 01:05 AM | LINK

     Hello all,

     I am fiddling with a Template created in Expression Blend 2.5 June Preview. It is located in a UserControl called Timeline. If I apply the Template using XAML on a  Button Element it works great. If I create a button element in my code behind and apply the template using the code:

     

                Jerbil.Width = 100;
    Jerbil.Height = 100;
    Jerbil.Content = "Howdy!";
    Jerbil.Template = (ControlTemplate)(Application.Current.Resources["TimeLineButtonTemplate"]);
    this.TimelineLayoutRoot.Children.Add(Jerbil);
    nothing happens - the style stays the same. The object "Jerbil" is a TimeLineButton, subclass of Button. The TimeLineButton class is really basic at this point:  
        public class TimeLineButton : Button
    {
    public event EventHandler LeftDrag;
    public event EventHandler RightDrag;

    public TimeLineButton()
    {
    SetTemplate("TimeLineButtonTemplate");
    }

    private void SetTemplate(string template)
    {
    this.Template = (ControlTemplate)(Application.Current.Resources[template]);
    }
     Obviously changing the template in the constructor doesn't work either. How is this done? My template code is below:
      <UserControl.Resources>

    <ControlTemplate x:Key="TimelineButtonTemplate" TargetType="Button">
    <Grid>
    <vsm:VisualStateManager.VisualStateGroups>
    <vsm:VisualStateGroup x:Name="FocusStates">
    <vsm:VisualState x:Name="Unfocused">
    <Storyboard/>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Focused">
    <Storyboard/>
    </vsm:VisualState>
    </vsm:VisualStateGroup>
    <vsm:VisualStateGroup x:Name="CommonStates">
    <vsm:VisualState x:Name="MouseOver">
    <Storyboard>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF494FEA"/>
    <SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF494FEA"/>
    </ColorAnimationUsingKeyFrames>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFFFFFF"/>
    <SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFFFFFF"/>
    </ColorAnimationUsingKeyFrames>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF4950FF"/>
    <SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF4950FF"/>
    </ColorAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Offset)">
    <SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="1"/>
    </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Pressed">
    <Storyboard>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF4950FF"/>
    </ColorAnimationUsingKeyFrames>
    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Offset)">
    <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    </DoubleAnimationUsingKeyFrames>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFFFFFF"/>
    </ColorAnimationUsingKeyFrames>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF494FEA"/>
    </ColorAnimationUsingKeyFrames>
    </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Selected">
    <Storyboard>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Duration="00:00:00.0010000">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#BF495000"/>
    </ColorAnimationUsingKeyFrames>
    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Duration="00:00:00.0010000">
    <SplineColorKeyFrame KeyTime="00:00:00" Value="#BF494F00"/>
    </ColorAnimationUsingKeyFrames>
    </Storyboard>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Disabled">
    <Storyboard/>
    </vsm:VisualState>
    <vsm:VisualState x:Name="Normal"/>
    </vsm:VisualStateGroup>
    </vsm:VisualStateManager.VisualStateGroups>
    <Rectangle HorizontalAlignment="Stretch" Margin="0,0,-115,-35" VerticalAlignment="Stretch" Stroke="#FF000000" StrokeThickness="2" x:Name="rectangle">
    <Rectangle.Fill>
    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    <GradientStop Color="#BF4950FF" Offset="0.991"/>
    <GradientStop Color="#BF494FEA" Offset="0"/>
    <GradientStop Color="#BFFFFFFF" Offset="0.653"/>
    </LinearGradientBrush>
    </Rectangle.Fill>
    </Rectangle>
    <ContentPresenter HorizontalAlignment="Center" Margin="0,0,0,0" x:Name="Text" VerticalAlignment="Center" FontWeight="Bold"/>
    <Border Cursor="SizeWE" Height="0" x:Name="Right_Edge" VerticalAlignment="Top" Background="#FF000000"/>
    <Border Cursor="SizeWE" Height="0" x:Name="Left_Edge" VerticalAlignment="Top"/>
    </Grid>
    </ControlTemplate>
    </UserControl.Resources>
    The template is in Timeline.xaml. Thanks for any help.
    Bradford 
  • sladapter

    sladapter

    All-Star

    43607 Points

    7907 Posts

    Re: Setting Button Template in Code-Behind

    Sep 16, 2008 02:33 AM | LINK

    I saw you are creating a custom control. Just put your Template in the generic.xaml file.

     <Style TargetType="yourcontrolnamespace:TimeLineButton>
            <Setter Property="Template">
                <Setter.Value>
                     <ControlTemplate TargetType="controls:TimeLineButton">   <!-- put your template here -->             

                    </ControlTemplate>
                </Setter.Value>
            </Setter>
    </Style> 
     public TimeLineButton()
    {
    DefaultStyleKey = typeof(TimeLineButton); // Make sure you have this line in the constructor
    }
     You do not need any code to set the template. This should do it.
    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question
  • elBradford

    elBradford

    Member

    6 Points

    9 Posts

    Re: Setting Button Template in Code-Behind

    Sep 16, 2008 11:38 PM | LINK

    Thank you for your help! I have created a generic.xaml and have posted the code below:

     

    <ResourceDictionary
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
    
        <Style TargetType="NewsPlayerAnnotator:TimeLineButton>
    	    <Setter Property="Template">
    		    <Setter.Value>
    			    <ControlTemplate TargetType="controls:TimeLineButton">
    				    <Grid>
    					    ...
                                        </Grid>
                                </ControlTemplate>
                        </Setter.Value>
               </Setter>
        </Style>
    </ResourceDictionary>
    I have also added  
    DefaultStyleKey = typeof(TimeLineButton);
    to the constructor as you suggested. Everything seems to be peachy until I try to add a TimeLineButton to the canvas. I have a method that fires on a click event, which has the code
    this.TimelineLayoutRoot.Children.Add(Jerbil);
    where Jerbil is a TimeLineButton. I create the Jerbil object, change its position, its height, its content, etc, but when I try to add it to the canvas it fails with  
    System.Exception was unhandled by user code

      Message="Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))"
    StackTrace:
    at MS.Internal.XcpImports.CheckHResult(UInt32 hr)
    at System.Windows.PresentationFrameworkCollection`1.AddDependencyObject(DependencyObject value)
    at System.Windows.Controls.UIElementCollection.Add(UIElement value)
    at NewsPlayerAnnotator.Timeline.clickme_Click(Object sender, RoutedEventArgs e)
    at System.Windows.Controls.Primitives.ButtonBase.OnClick()
    at System.Windows.Controls.Button.OnClick()
    at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
    at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(Object sender, MouseButtonEventArgs e)
    at System.Windows.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
    at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, String eventName)
    InnerException:
    I'm wondering what's wrong? I am getting some general errors in my generic.xaml but they aren't stopping the application from running. One is an error "the attachable property 'VisualStateGroups' was not found in type 'VisualStateManager' but I have that in my other projects and it doesn't really seem to mean anything.
     Any further help would be greatly appreciated!
     Bradford 
  • sladapter

    sladapter

    All-Star

    43607 Points

    7907 Posts

    Re: Setting Button Template in Code-Behind

    Sep 17, 2008 01:42 AM | LINK

     Did you first test to put a TimeLineButton in your Page.Xaml?

    Here is my test XAML:

    <Grid x:Name="LayoutRoot" Background="White" >
            <controls:TimeLineButton Width="200" Height="20"/>
        </Grid>

     

    Here is the Style I put in the generic.xaml:

    <Style TargetType="NewsPlayerAnnotator:TimeLineButton">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="NewsPlayerAnnotator:TimeLineButton">
                    <Grid>
                    <vsm:VisualStateManager.VisualStateGroups>
                        <vsm:VisualStateGroup x:Name="FocusStates">
                            <vsm:VisualState x:Name="Unfocused">
                                <Storyboard/>
                            </vsm:VisualState>
                            <vsm:VisualState x:Name="Focused">
                                <Storyboard/>
                            </vsm:VisualState>
                        </vsm:VisualStateGroup>
                        <vsm:VisualStateGroup x:Name="CommonStates">
                            <vsm:VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
            <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF494FEA"/>
            <SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF494FEA"/>
            </ColorAnimationUsingKeyFrames>
            <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
                <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFFFFFF"/>
                <SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFFFFFF"/>
            </ColorAnimationUsingKeyFrames>
            <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
                <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF4950FF"/>
                <SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF4950FF"/>
            </ColorAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Offset)">
                <SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="1"/>
            </DoubleAnimationUsingKeyFrames>
            </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Pressed">
                <Storyboard>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
                        <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF4950FF"/>
                    </ColorAnimationUsingKeyFrames>
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Offset)">
                        <SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
                    </DoubleAnimationUsingKeyFrames>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
                        <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFFFFFF"/>
                    </ColorAnimationUsingKeyFrames>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
                        <SplineColorKeyFrame KeyTime="00:00:00" Value="#FF494FEA"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Selected">
                <Storyboard>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Duration="00:00:00.0010000">
                        <SplineColorKeyFrame KeyTime="00:00:00" Value="#BF495000"/>
                    </ColorAnimationUsingKeyFrames>
                    <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Duration="00:00:00.0010000">
                        <SplineColorKeyFrame KeyTime="00:00:00" Value="#BF494F00"/>
                    </ColorAnimationUsingKeyFrames>
                </Storyboard>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Disabled">
                <Storyboard/>
            </vsm:VisualState>
            <vsm:VisualState x:Name="Normal"/>
            </vsm:VisualStateGroup>
            </vsm:VisualStateManager.VisualStateGroups>
            <Rectangle HorizontalAlignment="Stretch" Margin="0,0,-115,-35" VerticalAlignment="Stretch" Stroke="#FF000000" StrokeThickness="2" x:Name="rectangle">
                <Rectangle.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#BF4950FF" Offset="0.991"/>
                        <GradientStop Color="#BF494FEA" Offset="0"/>
                        <GradientStop Color="#BFFFFFFF" Offset="0.653"/>
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>
            <ContentPresenter HorizontalAlignment="Center" Margin="0,0,0,0" x:Name="Text" VerticalAlignment="Center" FontWeight="Bold"/>
            <Border Cursor="SizeWE" Height="0" x:Name="Right_Edge" VerticalAlignment="Top" Background="#FF000000"/>
            <Border Cursor="SizeWE" Height="0" x:Name="Left_Edge" VerticalAlignment="Top"/>
            </Grid>
            </ControlTemplate>
                </Setter.Value>
             </Setter>
        </Style>

     public class TimeLineButton: Button
        {
            public TimeLineButton()
            {
                this.DefaultStyleKey = typeof(TimeLineButton);
            }

        }

    Everything works fine. Check you button event handler. Seems something wrong with Event handler.

     

    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question
  • elBradford

    elBradford

    Member

    6 Points

    9 Posts

    Re: Re: Setting Button Template in Code-Behind

    Sep 18, 2008 05:16 PM | LINK

    Thanks again for your reply. I used your code for the generic.xaml, added a TimeLineButton element to the xaml file for my user control, and I have the following class defined in my code behind:

          public class TimeLineButton : Button
        {
            public event EventHandler LeftDrag;
            public event EventHandler RightDrag;

            public TimeLineButton()
            {
                DefaultStyleKey = typeof(TimeLineButton);
            }
        }

     

    When I run my project I get the error "AG_E_UNKNOWN_ERROR" on InitializeComponent on my user control constructor, apparently as it initializes the xaml. When I remove the TimeLineButton from the xaml it runs successfully, however I get the same original catastrophic failure when I try to add a TimeLineButton element to the canvas. Strange! Any additional thoughts?

  • sladapter

    sladapter

    All-Star

    43607 Points

    7907 Posts

    Re: Re: Setting Button Template in Code-Behind

    Sep 18, 2008 05:21 PM | LINK

    When you add TimeLineButton to your UserControl, did you define the namespace prefix?

    <UserControl xmlns:controls="clr-namespace;YourTimeLineButtonNameSpace;assembly=YourTimeLineButtonName" 
        x:Class="YOurNameSpace.YourUserContro"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        >

     <Grid x:Name="LayoutRoot" Background="White" >
            <controls:TimeLineButton Width="200" Height="20"/>
        </Grid>

    </UserControl>

    Sally Xu
    Software Engineer
    Aprimo, Inc

    Please remember to mark the replies as answers if they answered your question
  • elBradford

    elBradford

    Member

    6 Points

    9 Posts

    Re: Re: Setting Button Template in Code-Behind

    Sep 18, 2008 05:35 PM | LINK

    I found the problem. I figured the problem was with my code, and it was. I hadn't set up my generic.xaml correctly with the correct namespaces. I am a beginner and wasn't aware of the correct format for a generic.xaml file. So after looking at your sample, I found that I didn't have the correct xmlns namespace in the parent ResourceDictionary. After adding that it worked beautifully. Having that set up correctly, it worked great. However now the problem is that the template events such as mouseover and click don't trigger changes in the template like it was programmed to do. Perhaps I lost some of that when I transferred to a generic.xaml from the App.xaml.

     And it looks like you replied with a post (I just got the email) that suggests just what I found out. Thank you for your quick reply.

     

    Bradford

  • elBradford

    elBradford

    Member

    6 Points

    9 Posts

    Re: Re: Setting Button Template in Code-Behind

    Sep 18, 2008 09:38 PM | LINK

    When I add my TimeLineButtons through code behind to the canvas the isEnabled flag is false by default - so it sits in the "Disabled" state.While isEnabled = false no events fire, including click, mouseEnter, etc obviously.

    It took me a bit to figure this out (longer than it should have), but you just have to set the flag manually in the constructor for the Button subclass, in this case TimeLineButton.

     

            public TimeLineButton()
            {
                DefaultStyleKey = typeof(TimeLineButton);
                this.IsEnabled = true;
            }
      Bradford