使用 ObjectAnimationUsingKeyFrames 可以做到这一点,但是这样做非常困难,会导致你扯掉头发,经常让你的视觉工作室崩溃,并且让你用简单的方法做这件事几乎没有什么好处。
简单的方法:
public class TestSwapContentControl : ContentControl
{
object StoredOriginalContent;
public object FullContent
{
get { return (object)GetValue(FullContentProperty); }
set { SetValue(FullContentProperty, value); }
}
// Using a DependencyProperty as the backing store for FullContent. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FullContentProperty =
DependencyProperty.Register(
"FullContent"
, typeof(object)
, typeof(TestSwapContentControl)
, null);
public void SwitchToFullContent()
{
if (FullContent != null)
{
StoredOriginalContent = Content;
Content = FullContent;
}
}
public void SwitchToNormalContent()
{
if(StoredOriginalContent != null)
{
Content = StoredOriginalContent;
}
}
}
然后要使用的xaml:
<local:TestSwapContentControl x:Name="mySwitch">
<Rectangle Height="50" Width="100" Fill="Black" />
<local:TestSwapContentControl.FullContent>
<StackPanel>
<TextBlock>1</TextBlock>
<TextBlock>2</TextBlock>
<TextBlock>3</TextBlock>
<TextBlock>4</TextBlock>
<Rectangle Height="50" Width="100" Fill="Red" />
</StackPanel>
</local:TestSwapContentControl.FullContent>
</local:TestSwapContentControl>
在页面中使用以下cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
if (myTempBool)
{
mySwitch.SwitchToFullContent();
myTempBool = false;
}
else
{
mySwitch.SwitchToNormalContent();
myTempBool = true;
}
}
现在,如果您真的需要让其他开发人员完全可以扩展控件,您将需要使用 visualstatemenager,但它确实是个婊子。如果您不知道如何通过 generic.xaml 设置可视状态管理器和状态,这里有一个操作指南:
http://scorbs.com/2008/06/11/parts-states-model-with-visualstatemanager-part-1-of/
这是一个工作示例,但它并不完美,因为我似乎无法直接设置 ContentPresenter 的内容。
using System.Windows;
using System.Windows.Controls;
namespace SilverlightTestApplication
{
[TemplateVisualState(Name="Normal", GroupName="SizeStates")]
[TemplateVisualState(Name="Expanded", GroupName="SizeStates")]
public class TestVSMControl : ContentControl
{
public object SmallContent
{
get { return (object)GetValue(SmallContentProperty); }
set { SetValue(SmallContentProperty, value); }
}
// Using a DependencyProperty as the backing store for SmallContent. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SmallContentProperty =
DependencyProperty.Register("SmallContent", typeof(object), typeof(TestVSMControl), null);
public object LargeContent
{
get { return (object)GetValue(LargeContentProperty); }
set { SetValue(LargeContentProperty, value); }
}
// Using a DependencyProperty as the backing store for LargeContent. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LargeContentProperty =
DependencyProperty.Register("LargeContent", typeof(object), typeof(TestVSMControl), null);
public bool Pressed
{
get { return (bool)GetValue(PressedProperty); }
set { SetValue(PressedProperty, value); }
}
// Using a DependencyProperty as the backing store for Pressed. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PressedProperty =
DependencyProperty.Register("Pressed", typeof(bool), typeof(TestVSMControl),
new PropertyMetadata(new PropertyChangedCallback(PressedPropertyChanged)));
static void PressedPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var me = sender as TestVSMControl;
me.ChangeState();
}
public TestVSMControl()
{
DefaultStyleKey = typeof(TestVSMControl);
}
void ChangeState()
{
GoToState(true);
}
private void GoToState(bool useTransitions)
{
if (Pressed)
{
VisualStateManager.GoToState(this, "Normal", useTransitions);
}
else
{
VisualStateManager.GoToState(this, "Expanded", useTransitions);
}
}
}
}
在您的 generic.xaml 中(包括 xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"):
<Style TargetType="local:TestVSMControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TestVSMControl">
<StackPanel>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="SizeStates">
<vsm:VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Content" Storyboard.TargetName="myContentPresenter" BeginTime="00:00:00" Duration="00:00:00.0010000" >
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0">
<DiscreteObjectKeyFrame.Value>
<StackPanel>
<TextBlock>Rararasputin</TextBlock>
<Button Content="{TemplateBinding SmallContent}" />
</StackPanel>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="Expanded">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Content" Storyboard.TargetName="myContentPresenter" BeginTime="00:00:00" Duration="00:00:00.0010000" >
<ObjectAnimationUsingKeyFrames.KeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0" >
<DiscreteObjectKeyFrame.Value>
<StackPanel>
<TextBlock>Other one</TextBlock>
<Button Content="{TemplateBinding LargeContent}" />
</StackPanel>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames.KeyFrames>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="myContentPresenter" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
以及如何在您的页面中使用:
<local:TestVSMControl x:Name="myVSMControl" Height="200">
<local:TestVSMControl.SmallContent>
<Rectangle Height="50" Width="100" Fill="Red" />
</local:TestVSMControl.SmallContent>
<local:TestVSMControl.LargeContent>
<Rectangle Height="50" Width="100" Fill="Green" />
</local:TestVSMControl.LargeContent>
</local:TestVSMControl>
<Button Content="Swap" x:Name="VSMButton" Click="VSMButton_Click" />
在您的页面中包含以下内容:
private void VSMButton_Click(object sender, RoutedEventArgs e)
{
myVSMControl.Pressed = !myVSMControl.Pressed;
}