metro 里面自定义双面控件,正方面的
先看generic。XAML
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<Style TargetType="local:CustomControl1"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:CustomControl1"> <Grid> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="ViewStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="0:0:0.7" To="Flipped"> <Storyboard> <DoubleAnimation Storyboard.TargetName="FlipButtonTransform" Storyboard.TargetProperty="Angle" To="90" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </VisualTransition> <VisualTransition GeneratedDuration="0:0:0.7" To="Normal"> <Storyboard> <DoubleAnimation Storyboard.TargetName="FlipButtonTransform" Storyboard.TargetProperty="Angle" To="-90" Duration="0:0:0.2"></DoubleAnimation> </Storyboard> </VisualTransition> </VisualStateGroup.Transitions> <VisualState x:Name="Normal"> <Storyboard> <DoubleAnimation Storyboard.TargetName="BackContent" Storyboard.TargetProperty="Opacity" To="0" Duration="0" ></DoubleAnimation> </Storyboard> </VisualState> <VisualState x:Name="Flipped"> <Storyboard> <DoubleAnimation Storyboard.TargetName="FlipButtonTransform" Storyboard.TargetProperty="Angle" To="90" Duration="0"></DoubleAnimation> <DoubleAnimation Storyboard.TargetName="FrontContent" Storyboard.TargetProperty="Opacity" To="0" Duration="0"></DoubleAnimation> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <!-- This is the front content. --> <Border x:Name="FrontContent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" > <ContentPresenter Content="{TemplateBinding FrontContent}"> </ContentPresenter> </Border> <!-- This is the back content. --> <Border x:Name="BackContent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}" > <ContentPresenter Content="{TemplateBinding BackContent}"> </ContentPresenter> </Border> <!-- This the flip button. --> <ToggleButton Grid.Row="1" x:Name="FlipButton" RenderTransformOrigin="0.5,0.5" Margin="0,10,0,0" Width="19" Height="19"> <ToggleButton.Template> <ControlTemplate> <Grid> <Ellipse Stroke="#FFA9A9A9" Fill="AliceBlue" /> <Path Data="M1,1.5L4.5,5 8,1.5" Stroke="#FF666666" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center"> </Path> </Grid> </ControlTemplate> </ToggleButton.Template> <ToggleButton.RenderTransform> <RotateTransform x:Name="FlipButtonTransform" Angle="-90"></RotateTransform> </ToggleButton.RenderTransform> </ToggleButton> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style>
然后是cs 文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
namespace Tiles { [TemplatePart(Name = "FlipButton", Type = typeof(ToggleButton)), TemplatePart(Name = "FlipButtonAlternate", Type = typeof(ToggleButton)), TemplateVisualState(Name = "Normal", GroupName = "ViewStates"), TemplateVisualState(Name = "Flipped", GroupName = "ViewStates")] public sealed class CustomControl1 : Control { public CustomControl1() { this.DefaultStyleKey = typeof(CustomControl1); } static CustomControl1() { } public static readonly DependencyProperty FrontContentProperty = DependencyProperty.Register("FrontContent", typeof(object), typeof(CustomControl1), null); public static readonly DependencyProperty BackContentProperty = DependencyProperty.Register("BackContent", typeof(object), typeof(CustomControl1), null); public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(CustomControl1), null); public static readonly DependencyProperty IsFlippedProperty = DependencyProperty.Register("IsFlipped", typeof(bool), typeof(CustomControl1), null); public object FrontContent { get { return GetValue(FrontContentProperty); } set { SetValue(FrontContentProperty, value); } } public object BackContent { get { return GetValue(BackContentProperty); } set { SetValue(BackContentProperty, value); } } public CornerRadius CornerRadius { get { return (CornerRadius)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, value); } } public bool IsFlipped { get { return (bool)GetValue(IsFlippedProperty); } set { SetValue(IsFlippedProperty, value); ChangeVisualState(true); } } protected override void OnApplyTemplate() { base.OnApplyTemplate(); ToggleButton flipButton = base.GetTemplateChild("FlipButton") as ToggleButton; if (flipButton != null) flipButton.Click += flipButton_Click; // Allow for two flip buttons if needed (one for each side of the panel). // This is an optional design, as the control consumer may use template // that places the flip button outside of the panel sides, like the // default template does. ToggleButton flipButtonAlternate = base.GetTemplateChild("FlipButtonAlternate") as ToggleButton; if (flipButtonAlternate != null) flipButtonAlternate.Click += flipButton_Click; this.ChangeVisualState(false); } private void flipButton_Click(object sender, RoutedEventArgs e) { this.IsFlipped = !this.IsFlipped; } private void ChangeVisualState(bool useTransitions) { if (!this.IsFlipped) { VisualStateManager.GoToState(this, "Normal", useTransitions); } else { VisualStateManager.GoToState(this, "Flipped", useTransitions); } // Disable flipped side to prevent tabbing to invisible buttons. UIElement front = FrontContent as UIElement; if (front != null) { if (IsFlipped) { front.Visibility = Visibility.Collapsed; } else { front.Visibility = Visibility.Visible; } } UIElement back = BackContent as UIElement; if (back != null) { if (IsFlipped) { back.Visibility = Visibility.Visible; } else { back.Visibility = Visibility.Collapsed; } } } } }
分析一下,注册两个object 类型DependencyProperty,
public static readonly DependencyProperty FrontContentProperty = DependencyProperty.Register("FrontContent", typeof(object), typeof(CustomControl1), null);
public object FrontContent
{
get
{
return GetValue(FrontContentProperty);
}
set
{
SetValue(FrontContentProperty, value);
}
}
重写OnApplyTemplate 这个方法
然后控制VisualState,
private void ChangeVisualState(bool useTransitions)
{
if (!this.IsFlipped)
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Flipped", useTransitions);
}
// Disable flipped side to prevent tabbing to invisible buttons.
UIElement front = FrontContent as UIElement;
if (front != null)
{
if (IsFlipped)
{
front.Visibility = Visibility.Collapsed;
}
else
{
front.Visibility = Visibility.Visible;
}
}
UIElement back = BackContent as UIElement;
if (back != null)
{
if (IsFlipped)
{
back.Visibility = Visibility.Visible;
}
else
{
back.Visibility = Visibility.Collapsed;
}
}
}
分别设置 backcontent 和frontcontent的可见性
然后是调用这个自定义控件的方法
<lib:CustomControl1 x:Name="panel" BorderBrush="DarkOrange" BorderThickness="3" IsFlipped="True"
Template="{StaticResource AlternateTemplate}" CornerRadius="4" Margin="10">
<lib:CustomControl1.Projection>
<PlaneProjection/>
</lib:CustomControl1.Projection>
<lib:CustomControl1.FrontContent>
<StackPanel Margin="6">
<TextBlock TextWrapping="Wrap" Margin="3" FontSize="16" Foreground="DarkOrange">This is the front side of the FlipPanel.</TextBlock>
<Button Margin="3" Padding="3" Content="Button One"></Button>
<Button Margin="3" Padding="3" Content="Button Two"></Button>
<Button Margin="3" Padding="3" Content="Button Three"></Button>
<Button Margin="3" Padding="3" Content="Button Four"></Button>
</StackPanel>
</lib:CustomControl1.FrontContent>
<lib:CustomControl1.BackContent>
<Grid Margin="6">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock TextWrapping="Wrap" Margin="3" FontSize="16" Foreground="DarkMagenta">This is the back side of the FlipPanel.</TextBlock>
<Button Grid.Row="2" Margin="3" Padding="10" Content="Flip Back to Front" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Click_1"></Button>
</Grid>
</lib:CustomControl1.BackContent>
</lib:CustomControl1>
控制正反两面的可见性
<ControlTemplate x:Key="AlternateTemplate" TargetType="lib:CustomControl1">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ViewStates">
<VisualState x:Name="Normal">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="FrontContentTransform"
Storyboard.TargetProperty="ScaleY" To="1" ></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="BackContentTransform"
Storyboard.TargetProperty="ScaleY" To="0" ></DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="Flipped">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="FrontContentTransform"
Storyboard.TargetProperty="ScaleY" To="0" ></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="BackContentTransform"
Storyboard.TargetProperty="ScaleY" To="1" ></DoubleAnimation>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<!-- This is the front content. -->
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Background="{TemplateBinding Background}"
>
<Border.RenderTransform>
<ScaleTransform x:Name="FrontContentTransform"></ScaleTransform>
</Border.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ContentPresenter
Content="{TemplateBinding FrontContent}">
</ContentPresenter>
<Rectangle Grid.Row="1" Stretch="Fill" Fill="LightSteelBlue"></Rectangle>
<ToggleButton Grid.Row="1" x:Name="FlipButton" Margin="5" Padding="15,0"
Content="˄" FontWeight="Bold" FontSize="12" HorizontalAlignment="Right">
</ToggleButton>
</Grid>
</Border>
<!-- This is the back content. -->
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Background="{TemplateBinding Background}" RenderTransformOrigin="0,1">
<Border.RenderTransform>
<ScaleTransform x:Name="BackContentTransform" ScaleY="0"></ScaleTransform>
</Border.RenderTransform>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Rectangle Stretch="Fill" Fill="LightSteelBlue"></Rectangle>
<ToggleButton x:Name="FlipButtonAlternate" Margin="5" Padding="15,0"
Content="˅" FontWeight="Bold" FontSize="12" HorizontalAlignment="Right">
</ToggleButton>
<ContentPresenter Grid.Row="1"
Content="{TemplateBinding BackContent}">
</ContentPresenter>
</Grid>
</Border>
</Grid>
</ControlTemplate>
控制设置scaley 从1,到0
<DoubleAnimation Storyboard.TargetName="FrontContentTransform"
Storyboard.TargetProperty="ScaleY" To="1" ></DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="BackContentTransform"
Storyboard.TargetProperty="ScaleY" To="0" ></DoubleAnimation>