我使用这段代码来设置可见性变化的动画。
public class VisibilityAnimation : DependencyObject
{
public enum AnimationType
{
None,
Fade
}
private const int AnimationDuration = 1000;
private static readonly Dictionary<FrameworkElement, bool> _hookedElements =
new Dictionary<FrameworkElement, bool>();
public static AnimationType GetAnimationType(DependencyObject obj)
{
return (AnimationType)obj.GetValue(AnimationTypeProperty);
}
public static void SetAnimationType(DependencyObject obj, AnimationType value)
{
obj.SetValue(AnimationTypeProperty, value);
}
public static readonly DependencyProperty AnimationTypeProperty =
DependencyProperty.RegisterAttached(
"AnimationType",
typeof(AnimationType),
typeof(VisibilityAnimation),
new FrameworkPropertyMetadata(AnimationType.None,
new PropertyChangedCallback(OnAnimationTypePropertyChanged)));
private static void OnAnimationTypePropertyChanged(
DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
FrameworkElement frameworkElement = dependencyObject as FrameworkElement;
if (frameworkElement == null)
{
return;
}
// If AnimationType is set to True on this framework element,
if (GetAnimationType(frameworkElement) != AnimationType.None)
{
// Add this framework element to hooked list
HookVisibilityChanges(frameworkElement);
}
else
{
// Otherwise, remove it from the hooked list
UnHookVisibilityChanges(frameworkElement);
}
}
private static void HookVisibilityChanges(FrameworkElement frameworkElement)
{
_hookedElements.Add(frameworkElement, false);
}
private static void UnHookVisibilityChanges(FrameworkElement frameworkElement)
{
if (_hookedElements.ContainsKey(frameworkElement))
{
_hookedElements.Remove(frameworkElement);
}
}
static VisibilityAnimation()
{
// Here we "register" on Visibility property "before change" event
UIElement.VisibilityProperty.AddOwner(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(
Visibility.Visible,
VisibilityChanged,
CoerceVisibility));
}
private static void VisibilityChanged(
DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
// Ignore
}
private static object CoerceVisibility(
DependencyObject dependencyObject,
object baseValue)
{
// Make sure object is a framework element
FrameworkElement frameworkElement = dependencyObject as FrameworkElement;
if (frameworkElement == null)
{
return baseValue;
}
// Cast to type safe value
Visibility visibility = (Visibility)baseValue;
// If Visibility value hasn't change, do nothing.
// This can happen if the Visibility property is set using data binding
// and the binding source has changed but the new visibility value
// hasn't changed.
if (visibility == frameworkElement.Visibility || visibility == Visibility.Collapsed) //Aggiungo da cri..x fare l'effetto solo sul fade in
{
return baseValue;
}
// If element is not hooked by our attached property, stop here
if (!IsHookedElement(frameworkElement))
{
return baseValue;
}
// Update animation flag
// If animation already started, don't restart it (otherwise, infinite loop)
if (UpdateAnimationStartedFlag(frameworkElement))
{
return baseValue;
}
// If we get here, it means we have to start fade in or fade out animation.
// In any case return value of this method will be Visibility.Visible,
// to allow the animation.
DoubleAnimation doubleAnimation = new DoubleAnimation
{
Duration = new Duration(TimeSpan.FromMilliseconds(AnimationDuration))
};
// When animation completes, set the visibility value to the requested
// value (baseValue)
doubleAnimation.Completed += (sender, eventArgs) =>
{
if (visibility == Visibility.Visible)
{
// In case we change into Visibility.Visible, the correct value
// is already set, so just update the animation started flag
UpdateAnimationStartedFlag(frameworkElement);
}
else
{
// This will trigger value coercion again
// but UpdateAnimationStartedFlag() function will reture true
// this time, thus animation will not be triggered.
if (BindingOperations.IsDataBound(frameworkElement,
UIElement.VisibilityProperty))
{
// Set visiblity using bounded value
Binding bindingValue =
BindingOperations.GetBinding(frameworkElement,
UIElement.VisibilityProperty);
BindingOperations.SetBinding(frameworkElement,
UIElement.VisibilityProperty, bindingValue);
}
else
{
// No binding, just assign the value
frameworkElement.Visibility = visibility;
}
}
};
if (visibility == Visibility.Collapsed || visibility == Visibility.Hidden)
{
// Fade out by animating opacity
doubleAnimation.From = 1.0;
doubleAnimation.To = 0.0;
}
else
{
// Fade in by animating opacity
doubleAnimation.From = 0.0;
doubleAnimation.To = 1.0;
}
// Start animation
frameworkElement.BeginAnimation(UIElement.OpacityProperty, doubleAnimation);
// Make sure the element remains visible during the animation
// The original requested value will be set in the completed event of
// the animation
return Visibility.Visible;
}
private static bool IsHookedElement(FrameworkElement frameworkElement)
{
return _hookedElements.ContainsKey(frameworkElement);
}
private static bool UpdateAnimationStartedFlag(FrameworkElement frameworkElement)
{
bool animationStarted = (bool)_hookedElements[frameworkElement];
_hookedElements[frameworkElement] = !animationStarted;
return animationStarted;
}
在xaml中我需要设置:VisibilityAnimation.AnimationType="Fade"
动画工作良好,但问题是,我有错误的标题。
我该如何解决这个问题?
Stack Overflow想要更多的细节来插入这段代码,但它都…写下这个短语,希望我能插入它。
根据MSDN (http://msdn.microsoft.com/en-us/library/ms754209%28v=vs.110%29.aspx) OverrideMetadata(与addownner相关)应该只从具有其属性Metadata被覆盖的类型的静态构造函数调用。我假设这条规则对于依赖属性的 addownner 方法也是一样的。
顺便问一下,你真的需要这样一个应用程序宽钩子吗?根据您所拥有的代码,看起来您真正需要的是为您所附加的属性分配的FrameworkElement的可见性更改通知。您可以通过以下方式实现这一点。 DependencyPropertyDescriptor.FromProperty (UIElement。VisibilityProperty typeof (FrameworkElement))。AddValueChange (frameworkElement回调)但是,因为你正在寻找的是一个应用程序范围挂钩可见性核心值回调FrameworkElements,你可以做这样的东西
static VisibilityAnimation()
{
// Here we "register" on Visibility property "before change" event
var desc = DependencyPropertyDescriptor.FromProperty(UIElement.VisibilityProperty, typeof(FrameworkElement));
desc.DesignerCoerceValueCallback += CoerceVisibility;
顺便说一下,这个属性所挂钩的FrameworkElements很有可能不会被垃圾收集,因为它们在_hookedElements字典中被搁置,直到AnimationType属性更改为AnimationType. none。
在静态构造函数中,将所有者类型更改为VisibilityAnimation
类
static VisibilityAnimation()
{
// Here we "register" on Visibility property "before change" event
UIElement.VisibilityProperty.AddOwner(
typeof(VisibilityAnimation),
new FrameworkPropertyMetadata(
Visibility.Visible,
VisibilityChanged,
CoerceVisibility));
}