Create Custom Control with Storyboard XAML - c#

I created a custom Control in a Windows 10 Universal App project, which is containing a Storyboard. The Code of the storyboard is looking like this:
<Storyboard x:Key="StatisticUpdateAnnimation">
<DoubleAnimationUsingKeyFrames EnableDependentAnimation="True" Storyboard.TargetProperty="(RingSlice.EndAngle)" Storyboard.TargetName="ringSlice">
<EasingDoubleKeyFrame KeyTime="0" Value="45"/>
<EasingDoubleKeyFrame KeyTime="0:0:2.2" Value="{Binding Angle}">
<EasingDoubleKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseIn"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
As you can see the x:Key = "StatisticUpdateAnnimation, the storyboard should be triggered only manually in C# code so I do not know how to Play this Storyboard after I created the Custom User Control in the Mainpage file like this:`
local:ProgressRing x:Name="Progress" Margin="7" VerticalAlignment="Top" HorizontalAlignment="Center" Tapped="ProgressRing_Tapped"/>
The style is like this
<Style TargetType="local:RingPresenter" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:RingPresenter">
<Grid>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Mode=TwoWay, ElementName=Representor, Path=EndAngle}" FontFamily="Vladimir Script" FontSize="48"></TextBlock>
<helper:RingSlice InnerRadius="100" Radius="150" StartAngle="0" EndAngle="{TemplateBinding Angle}" Fill="DarkCyan" x:Name="ringSlice">
</helper:RingSlice>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I access my storyboard?

Since I don't know what is your ProgressRing.HelperClasser, here I wrote a sample to show one method using Storyboard inside of the CustomControl. As we know, CustomControl is template control inside of the ResourceDictionary, we can for example use Storyboard inside of the ControlTemplate like this:
Generic.xaml
<Style TargetType="local:ProgressRing">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ProgressRing">
<Grid x:Name="RootGrid">
<Grid.Resources>
<Storyboard x:Key="std">
<ColorAnimation Storyboard.TargetName="brush" Storyboard.TargetProperty="Color"
Duration="0:0:2" From="LightBlue" To="Red" AutoReverse="True" />
</Storyboard>
</Grid.Resources>
<Ellipse Width="100" Height="100">
<Ellipse.Fill>
<SolidColorBrush x:Name="brush" />
</Ellipse.Fill>
</Ellipse>
<TextBlock Text="111" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And in the cs file of this Custom control:
public ProgressRing()
{
this.DefaultStyleKey = typeof(ProgressRing);
this.Loaded += ProgressRing_Loaded;
}
private void ProgressRing_Loaded(object sender, RoutedEventArgs e)
{
StoryboardPlay();
}
public void StoryboardPlay()
{
var rootGrid = this.GetTemplateChild("RootGrid") as Grid;
var std = rootGrid.Resources["std"] as Storyboard;
std.Begin();
}
I played this Storyboard here once it is loaded. Here the Control.GetTemplateChild method is useful, it helps find the named element in the instantiated ControlTemplate visual tree. Then you can get the resource inside this element.
Now if you use this custom control like this:
<local:ProgressRing x:Name="Progress" Margin="7" VerticalAlignment="Top" HorizontalAlignment="Center" Tapped="ProgressRing_Tapped" />
<Button VerticalAlignment="Bottom" Content="Click to play storyboard" Click="Button_Click" />
Now you can get the storyboard to play like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
Progress.StoryboardPlay();
}

Related

Pivot control customization on UWP

Basically I need to customize the pivot control on my uwp app and I use the style of pivot from windows phone 8.1. And it looks like this eventually(the yellow part is the content of the pivot item, I just use color to differentiate the header and the content)
But right now it does not meet the require of the original design. So I have two questions here:
1.How do I limit user flick the pivot in one direction? For example, users could only flick the control from left to right because the yellow content part will move to left and cover the header if the pivot is flicked from the right to the left. The content, which is the yellow part, will move entirely along with your finger and the other covered pivot header will be shown because the yellow part moves away, as you can see on the image. This is the reason why I care about the swiping direction because if you swipe left, the yellow part will covers part of the header before the gesture is done(which is not showing up in the image).
2.How to change the foreground color of the unselected pivotitem header? Right now as you can see, during the flicking process, the yellow content part will move away and the unselected header will be shown. That looks weird and it is not a good design at all. The unselected header is suppose to be transparent or be the same as the background color of the page.
Here is the code of the style:
<Style x:Key="PivotStyle1" TargetType="Pivot">
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="Foreground" Value="{ThemeResource PivotForegroundThemeBrush}"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Pivot">
<Grid x:Name="RootElement" Background="{TemplateBinding Background}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Orientation">
<VisualState x:Name="Portrait">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" Storyboard.TargetName="TitleContentControl">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotPortraitThemePadding}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Landscape">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" Storyboard.TargetName="TitleContentControl">
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource PivotLandscapeThemePadding}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentControl x:Name="TitleContentControl" ContentTemplate="{TemplateBinding TitleTemplate}" Content="{TemplateBinding Title}" Style="{StaticResource PivotTitleContentControlStyle}"/>
<ScrollViewer x:Name="ScrollViewer" HorizontalSnapPointsAlignment="Center" HorizontalSnapPointsType="MandatorySingle" HorizontalScrollBarVisibility="Hidden" Margin="{TemplateBinding Padding}" Grid.Row="1" Template="{StaticResource ScrollViewerScrollBarlessTemplate}" VerticalSnapPointsType="None" VerticalScrollBarVisibility="Disabled" VerticalScrollMode="Disabled" VerticalContentAlignment="Stretch" ZoomMode="Disabled">
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch">
<PivotHeaderPanel x:Name="Header">
<PivotHeaderPanel.RenderTransform>
<CompositeTransform x:Name="HeaderTranslateTransform" TranslateX="0"/>
</PivotHeaderPanel.RenderTransform>
</PivotHeaderPanel>
<ItemsPresenter x:Name="PivotItemPresenter">
<ItemsPresenter.RenderTransform>
<TranslateTransform x:Name="ItemsPresenterTranslateTransform" X="0"/>
</ItemsPresenter.RenderTransform>
</ItemsPresenter>
</PivotPanel>
</ScrollViewer>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And the XAML code for the pivot control:
<Pivot Style="{StaticResource PivotStyle1}">
<Pivot.HeaderTemplate>
<DataTemplate>
<Grid Height="auto">
<Grid.RowDefinitions>
<RowDefinition Height="21*"/>
<RowDefinition Height="299*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="19*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding}"
Margin="14,50,9,-120"
Grid.Row="1"
HorizontalAlignment="Center"
FontSize="48"
FontFamily="ms-appx:NotoSansCJKsc-Black.otf#Noto Sans CJK SC"
TextWrapping="Wrap"
LineStackingStrategy="BlockLineHeight"
LineHeight="49" Width="48"
Height="auto"/>
</Grid>
</DataTemplate>
</Pivot.HeaderTemplate>
<PivotItem Header="评论" Margin="83,-47,0,0" Background="Yellow">
<Grid>
<ListView x:Name="listview" d:LayoutOverrides="TopPosition, BottomPosition" ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding Groups}" Margin="10,0,0,0"/>
</Grid>
</PivotItem>
<PivotItem Header="转发" Margin="93,-47,0,0" Background="Yellow">
<Grid>
<ListView x:Name="listview2" d:LayoutOverrides="TopPosition, BottomPosition" ItemTemplate="{StaticResource GroupTemplate}" ItemsSource="{Binding Groups}"/>
</Grid>
</PivotItem>
</Pivot>
For your first question, you have customize the style of the Pivot control, your gesture shown above works fine on the mobile emulator, but not on the local machine. This is the problem about ManipulationMode in the design of a Pivot control. Pivot control's Gesture is achieved inside it's style, so it is possible to manipulate it in one direction, but we need to find the key point in the style.
You can use Manipulation to do this. You can modify your style of Pivot control like this:
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch">
<PivotHeaderPanel x:Name="Header" ManipulationMode="None">
<PivotHeaderPanel.RenderTransform>
<CompositeTransform x:Name="HeaderTranslateTransform" TranslateX="0" />
</PivotHeaderPanel.RenderTransform>
</PivotHeaderPanel>
<ItemsPresenter x:Name="PivotItemPresenter" ManipulationMode="None">
<ItemsPresenter.RenderTransform>
<TranslateTransform x:Name="ItemsPresenterTranslateTransform" X="0" />
</ItemsPresenter.RenderTransform>
</ItemsPresenter>
</PivotPanel>
and use this Pivot control like this:
<Pivot Style="{StaticResource PivotStyle1}" x:Name="myPivot" ManipulationMode="TranslateX" ManipulationStarting="OnStarting" ManipulationCompleted="OnCompleted">
...
</Pivot>
And the code behind:
public double pointx1;
private void OnCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
var pointx2 = Window.Current.CoreWindow.PointerPosition.X;
if (pointx2 > pointx1)
{
if (myPivot.SelectedIndex == 0)
myPivot.SelectedIndex = 1;
else
myPivot.SelectedIndex = 0;
}
else
return;
}
private void OnStarting(object sender, ManipulationStartingRoutedEventArgs e)
{
pointx1 = Window.Current.CoreWindow.PointerPosition.X;
}
Here is also a workaround method to solve this problem, consider that there is no manipulation in the style of Pivot, you can achieve this using PointerPoint you can modify your style of Pivot control like this:
<PivotPanel x:Name="Panel" VerticalAlignment="Stretch" ManipulationMode="None">
<PivotHeaderPanel x:Name="Header">
<PivotHeaderPanel.RenderTransform>
<CompositeTransform x:Name="HeaderTranslateTransform" TranslateX="0" />
</PivotHeaderPanel.RenderTransform>
</PivotHeaderPanel>
<ItemsPresenter x:Name="PivotItemPresenter">
<ItemsPresenter.RenderTransform>
<TranslateTransform x:Name="ItemsPresenterTranslateTransform" X="0" />
</ItemsPresenter.RenderTransform>
</ItemsPresenter>
</PivotPanel>
and use this Pivot control like this:
<Pivot Style="{StaticResource PivotStyle1}" PointerReleased="OnPointerExited" PointerPressed="OnPointerPressed" x:Name="myPivot">
...
</Pivot>
And the code behind:
public PointerPoint pointer1;
private void OnPointerExited(object sender, PointerRoutedEventArgs e)
{
var pointer2 = e.GetCurrentPoint(myPivot);
var position1x = pointer1.Position.X;
var position2x = pointer2.Position.X;
if (position2x > position1x)
{
if (myPivot.SelectedIndex == 0)
myPivot.SelectedIndex = 1;
else
myPivot.SelectedIndex = 0;
}
else
return;
}
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
pointer1 = e.GetCurrentPoint(myPivot);
}
And for your second question, as #ganchito55 said, you can modify the style of PivotHeaderItem.
Update:
If you just don't want to see the header of the other item when you manipulate it, you can modify the PivotHeaderItem like this:
......
<Setter Property="FontWeight" Value="{ThemeResource PivotHeaderItemThemeFontWeight}" />
<Setter Property="CharacterSpacing" Value="{ThemeResource PivotHeaderItemCharacterSpacing}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="Transparent" />
<Setter Property="Padding" Value="{ThemeResource PivotHeaderItemMargin}" />
<Setter Property="Height" Value="48" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="IsTabStop" Value="False" />
......

how to move UI element with storyboard?

I've worked with Opacity property in storyboard
but I cant figure it out how to move an UI element like grid stackpanel button ..... in c#?
(I am writing the storyboard in c# not in xaml )
Well, that depends on your actual layout: Do you want to animate a button in a Grid or in a Canvas (could animate the Margin property or the Canvas.Left attached property, respectively)? Do you want to animate the property itself or a transform (the latter would animate a RenderTransform - specifically a TranslateTransform). You would use the RenderTransform if you still want to refer to the "old" position.
One simple way is:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<DoubleAnimation Storyboard.TargetName="myButton"
Storyboard.TargetProperty="(Canvas.Left)" From="1" To="350"
Duration="0:0:10" BeginTime="0:0:0"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<Canvas x:Name="myCanvas" Background="Yellow">
<Button x:Name="myButton" Width="100" Height="30" Canvas.Left="100" Canvas.Top="100" />
</Canvas>
</Grid>
</Window>
it would be better if you use blend for storyboard ..i have genrated a code for stackpanel movement towards right ..just check it..
you can go through this video aslo it's very good it will perfectly work in your case
<Page.Resources>
<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="hello">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="100"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Name="hello" Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" >
<StackPanel.RenderTransform>
<CompositeTransform/>
</StackPanel.RenderTransform>
<TextBlock Text="hello1" FontSize="50" />
<Button Content="Button" FontSize="50" Click="Button_Click_1" />
</StackPanel>
</Grid>
and to start do this on button click..
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Storyboard1.Begin();
}
for better understand just read about how to use blend..

disabling all clicks for a short period after clicking a image

I'm using multiple images to create something like a virtual keyboard. I wish to add a short period of time after a image is clicked, where at the short period of time, all clicks on images are disabled. Does any1 knows how to do it? Here's my code for one of the images.
<Button Grid.Column="2" Command="{Binding Path=PressAndRelease}" CommandParameter="Q" Style="{StaticResource TransparentButton}" Effect="{Binding}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image Name="imgNormalQ" Source="/wa;com/Images/alp/q.png" Height="127"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Panel.ZIndex" Value="999"/>
<Setter TargetName="imgPressedQ" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
in Silverlight I have done this using VisualStateManager
there is not much difference in WPF
edited
I have created sample Storyboard to disabled WPF UIElement.
<StackPanel>
<Border x:Name="MainContent">
<StackPanel x:Name="ButtonPanel">
<Button Width="100" Click="AnyButton_Click">Busy State 1</Button>
<Button Width="100" Click="AnyButton_Click">Busy State 2</Button>
<Button Width="100" Click="AnyButton_Click">Busy State 3</Button>
</StackPanel>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="BusyStates">
<VisualState x:Name="Ready" />
<VisualState x:Name="Busy">
<Storyboard>
<BooleanAnimationUsingKeyFrames Duration="0"
Storyboard.TargetName="ButtonPanel"
Storyboard.TargetProperty="IsEnabled">
<DiscreteBooleanKeyFrame KeyTime="0" Value="False"/>
</BooleanAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
<Button Width="100" x:Name="ClearButton" Click="ClearButton_Click">Ready</Button>
</StackPanel>
the VisualState named "Busy" will animate ButtonPanel.IsEnabled = false (at keytime=0)
here's basic code behind
private void AnyButton_Click(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToElementState(MainContent, "Busy", true);
}
private void ClearButton_Click(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToElementState(MainContent, "Ready", true);
}
PS. if you follow the MVVM. VisualStateManager responsible for View. it should be part of XAML not ViewModel

Storyboard Completed Event from Style?

I'm new to Storyboard animations but I think this might be a problem I can't workaround the easy way. Nevertheless I try my luck here, maybe some of you guys know how to help me.
My Scenario : I want to show a popup in my Application that has a fadein effect. I also want to do this via MVVM so my control that wraps the fadein effect and the popup should no use codebehind and my application should just need to reset the datacontext of this control to a new viewmodel to show a new message.
My Problem is that I cannot determine when the animation is finished because I need to set the fadein Animation in the style.
My XAML looks like this :
<UserControl.Resources>
<Style x:Key="popupStyle" TargetType="{x:Type Border}" >
<Style.Triggers>
<Trigger Property="Visibility" Value="Visible">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard x:Name="FadingStoryBoard">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.05" To="1" BeginTime="0:0:1" Duration="0:0:2.5" >
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="5" EasingMode="EaseIn" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" BeginTime="0:0:6" Duration="0:0:8.5" >
<DoubleAnimation.EasingFunction>
<ExponentialEase Exponent="15" EasingMode="EaseOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Popup Name="Popup" IsOpen="{Binding IsVisible}" Height="{Binding PopupHeight}" Width="{Binding PopupWidth}" VerticalOffset="{Binding PopupVerticalOffset}" HorizontalOffset="{Binding PopupHorizontalOffset}" PopupAnimation="Fade" AllowsTransparency="True">
<Border Style="{StaticResource popupStyle}" Name="PopupContent" Padding="1" BorderBrush="#000000" Background="AliceBlue" CornerRadius="5" BorderThickness="3,3,3,3">
<!-- Events -->
<interact:Interaction.Triggers>
<interact:EventTrigger EventName="PreviewMouseDown">
<cmd:EventToCommand Command="{Binding Path=PopupMouseDownCommand}" PassEventArgsToCommand="True" />
</interact:EventTrigger>
</interact:Interaction.Triggers>
<DockPanel Name="ContentContainer" Background="Black" LastChildFill="True">
<Image Source="{Binding MessageIcon}" DockPanel.Dock="Left" Margin="5,0,5,0" Width="32" Height="32" />
<StackPanel Background="Transparent" DockPanel.Dock="Right" Margin="3">
<TextBlock Name="PopupHeaderTextBlock" Margin="0,3,0,5" TextWrapping="Wrap" FontSize="10" Text="{Binding PopupHeaderText}" Foreground="White" Background="Transparent" />
<TextBlock Name="PopupTextBlock" Text="{Binding PopupText}" TextWrapping="Wrap" FontSize="10" Foreground="White" Background="Transparent" />
</StackPanel>
</DockPanel>
</Border>
</Popup>
Anyone any ideas how I can get a notification in my ViewModel when the Storyboard has finished ?
You can handle the Completed event on the storyboard.
Documentation Here: http://msdn.microsoft.com/en-us/library/system.windows.media.animation.timeline.completed.aspx
Here's the code to attach the event from the codebehind:
call from the constructor:
private void AttachToCompletedEvent()
{
Style popupStyle = Resources["popupStyle"];
TriggerBase trigger = popupStyle.Triggers[0];
BeginStoryboard action = trigger.EnterActions[0] as BeginStoryboard;
Storyboard storyboard = action.Storyboard;
storyboard.Completed += CompletedEventHandler;
}
I think that should work for the code you provided.

What can cause my template to be ignored in this Custom Control

EDIT: Original title: When I add a custom control based on a timer, my templates are ignored.
I'm working on the 70-511 training kit from Microsoft Press, and combined two practice exercises together from chapter 5.
The problem is that when I add the custom control to my MainWindow, it runs, but the triggers on the Button template are ignored. When the same control is removed, the triggers are honored.
For those who don't have access to the book, and don't feel like analyzing the code, it's a custom control with a label that has a dependency property setup to update on a timer object (once per second) with the current system time.
As you might infer from my attached code, the custom control is in a separate assembly referenced by the 5_3 project.
I'm a bit stumped on this one. What is causing this?
Here is the code:
MainWindow.xaml:
<Window x:Class="chapter5_3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:chapter5_3CustomControl;assembly=chapter5_4CustomControl">
<Window.Resources>
<ControlTemplate TargetType="{x:Type Button}" x:Key="ButtonTemplate">
<Border Name="Bord1" BorderBrush="Olive" BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<Rectangle Name="rect1">
<Rectangle.Fill>
<SolidColorBrush x:Name="rosyBrush" Color="RosyBrown"/>
</Rectangle.Fill>
</Rectangle>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Trigger.EnterActions>
<BeginStoryboard Name="bst2">
<Storyboard AutoReverse="False">
<ColorAnimation Duration="0:0:.3"
Storyboard.TargetProperty="Color"
Storyboard.TargetName="rosyBrush" >
<ColorAnimation.By>
<Color A="0" R="100" B="0" G="0"/>
</ColorAnimation.By>
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="bst2" />
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="bst1">
<Storyboard>
<ThicknessAnimation Storyboard.TargetName="Bord1"
Storyboard.TargetProperty="BorderThickness"
By=".1" Duration="0:0:.3" />
<ColorAnimation AutoReverse="False" To="DarkRed" Duration="0:0:.3"
Storyboard.TargetProperty="Color"
Storyboard.TargetName="rosyBrush" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<StopStoryboard BeginStoryboardName="bst1" />
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="rect1" Property="Fill" Value="Gray"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<Button Template="{StaticResource ResourceKey=ButtonTemplate}" Height="23" Width="100" BorderThickness="2" Name="btnHello" Content="Hello" IsEnabled="False">
</Button>
<ToolBarPanel>
<CheckBox IsChecked="True" Content="Enable Button" Name="cbEnabled" Checked="cbEnabled_Checked" Unchecked="cbEnabled_Checked"/>
</ToolBarPanel>
<my:CustomControl1 Name="customControl11" />
</Grid>
CustomControl1.xaml: (separate assembly)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:chapter5_3CustomControl">
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<TextBlock Foreground="{TemplateBinding Foreground}" HorizontalAlignment="Center"
Text="{Binding Path=Time}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
CustomControl.cs
public class CustomControl1 : Control
{
public static readonly DependencyProperty TimeProperty;
System.Timers.Timer myTimer = new System.Timers.Timer();
delegate void SetterDelegate();
static CustomControl1()
{
FrameworkPropertyMetadata metadata = new FrameworkPropertyMetadata();
TimeProperty = DependencyProperty.Register("Time", typeof(string), typeof(CustomControl1), metadata);
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
}
public CustomControl1()
{
myTimer.Elapsed += timer_elapsed;
myTimer.Interval = 1000;
myTimer.Start();
this.DataContext = this;
}
void TimeSetter()
{
SetValue(TimeProperty, DateTime.Now.ToLongTimeString());
}
void timer_elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Dispatcher.Invoke(new SetterDelegate(TimeSetter),
System.Windows.Threading.DispatcherPriority.Normal);
}
}
Edit:
I wanted to plug a free tool that I use called snoop! You can find it here, and I recommend it as it allows you to inspect your controls at runtime! Snoop Lives here at time of edit: http://snoopwpf.codeplex.com/ It has saved me a lot of time!
Because your Button and CustomControl are in the same row and column of the Grid, your CustomControl is probably covering the Button. You probably just can't see it.
If you set the Background of your CustomControl to say Red, then you will see what area it is covering.
You would need to ensure that the CustomControl doesn't cover the Button, if you want the Button to respond to mouse events. Alternatively, you can set IsHitTestVisible to false on your CustomControl or ensure it's Background is null.

Categories

Resources