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:
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"); }
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
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.
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?
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.
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;
}
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:
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 -->
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
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:
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.
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
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
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>
Software Engineer
Aprimo, Inc
Please remember to mark the replies as answers if they answered your question
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
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.
Bradford