2012-05-31 46 views
4

我试图在内容控件(如Button或ContentControl)更改其内容时触发动画。我最初的想法是这样做的:当ContentControl.Content被改变时开始动画

 <ContentControl x:Name="ContentElement"> 
      <ContentControl.Style> 
       <Style TargetType="ContentControl"> 
        <Setter Property="Template"> 
         <Setter.Value> 
          <ControlTemplate TargetType="ContentControl"> 
           <ContentPresenter x:Name="Content"> 
            <ContentPresenter.Triggers> 
             <EventTrigger RoutedEvent="WHATGOESHERE"> 
              <BeginStoryboard Storyboard="{StaticResource MyAnimation}" Storyboard.TargetName="Content"/> 
             </EventTrigger> 
            </ContentPresenter.Triggers> 
           </ContentPresenter> 
          </ControlTemplate> 
         </Setter.Value> 
        </Setter> 
       </Style> 
      </ContentControl.Style> 

      <Button Content="Hello"/> 
     </ContentControl> 

但我不知道当ContentPresenter更改/更新时会触发哪个事件。有任何想法吗?

回答

1

不幸的是,ContentChanged没有CLR事件(更不用说事件触发器需要RoutedEvent)。但是,考虑到您正在处理自定义控件,您可以覆盖Content属性的元数据并在控件中提供自己的回调。

这可能是你正在寻找here

显然什么他创造了一个CLR事件向外部传播内容的变化;你也可以使用RoutedEvent来代替。

上OverrideMetadata here

9

补充阅读你可以只写一个附加属性:

static class ContentControlExtensions 
{ 
    public static readonly DependencyProperty ContentChangedAnimationProperty = DependencyProperty.RegisterAttached(
     "ContentChangedAnimation", typeof(Storyboard), typeof(ContentControlExtensions), new PropertyMetadata(default(Storyboard), ContentChangedAnimationPropertyChangedCallback)); 

    public static void SetContentChangedAnimation(DependencyObject element, Storyboard value) 
    { 
     element.SetValue(ContentChangedAnimationProperty, value); 
    } 

    public static Storyboard GetContentChangedAnimation(DependencyObject element) 
    { 
     return (Storyboard)element.GetValue(ContentChangedAnimationProperty); 
    } 

    private static void ContentChangedAnimationPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) 
    { 
     var contentControl = dependencyObject as ContentControl; 
     if (contentControl == null) 
      throw new Exception("Can only be applied to a ContentControl"); 

     var propertyDescriptor = DependencyPropertyDescriptor.FromProperty(ContentControl.ContentProperty, 
      typeof (ContentControl)); 

     propertyDescriptor.RemoveValueChanged(contentControl, ContentChangedHandler); 
     propertyDescriptor.AddValueChanged(contentControl, ContentChangedHandler); 
    } 

    private static void ContentChangedHandler(object sender, EventArgs eventArgs) 
    { 
     var animateObject = (FrameworkElement) sender; 
     var storyboard = GetContentChangedAnimation(animateObject); 
     storyboard.Begin(animateObject); 
    } 
} 

,然后在XAML:

 <ContentControl Content="{Binding SelectedViewItem}"> 
      <extensions:ContentControlExtensions.ContentChangedAnimation> 
       <Storyboard> 
        <ThicknessAnimation To="0" From="30,0,-30,0" Duration="0:0:0.3" Storyboard.TargetProperty="Margin"/> 
       </Storyboard> 
      </extensions:ContentControlExtensions.ContentChangedAnimation> 
     </ContentControl> 

这是不是一个新的控制更容易和更短。

+0

如果将'Get..'和'Set ...'方法中的'DependencyObject'标注更改为'ContentControl',则不需要在回调方法中进行类型检查。 – gregsdennis

+2

优秀的例子,很好,很简单....对于新的WPF开发人员来说,它可能只是值得将xmlns:behavior =“clr-namespace:<您的应用程序名称空间>”添加到XAML的顶部..... – Monty

+1

这不是一种行为,而是一种附属财产。 –