C# 使用dependency属性在n秒后隐藏元素的可见性

C# 使用dependency属性在n秒后隐藏元素的可见性,c#,wpf,xaml,c#-4.0,attached-properties,C#,Wpf,Xaml,C# 4.0,Attached Properties,我的目标:我有一个按钮和一个图像图像将被隐藏,一旦用户将鼠标悬停在按钮上,则应显示图像。在用户将鼠标放在图像或按钮上之前,它应该是可见的。它应该在用户离开鼠标点6秒后隐藏图像(从按钮或图像)。鼠标在6秒前再次悬停并离开应重新启动计时器 我尝试的我已经有了一个可行的解决方案,使用AttachedProperty,但这并不有效。我感觉到由于这里的静态导致内存泄漏 public class MouseHoverBehavior { public static readonly Dependen

我的目标:我有一个
按钮
和一个
图像
<默认情况下,代码>图像将被
隐藏
,一旦用户将鼠标悬停在
按钮上
,则应显示
图像
。在用户将鼠标放在
图像
按钮
上之前,它应该是可见的。它应该在用户离开鼠标点6秒后隐藏图像(从按钮或图像)。鼠标在6秒前再次悬停并离开应重新启动计时器

我尝试的我已经有了一个可行的解决方案,使用
AttachedProperty
,但这并不有效。我感觉到由于这里的
静态
导致内存泄漏

public class MouseHoverBehavior
{
    public static readonly DependencyProperty ElementProperty = DependencyProperty.RegisterAttached(
        "Element", typeof(UIElement), typeof(MouseHoverBehavior), new UIPropertyMetadata(OnElementChanged));

    private static UIElement target;

    static MouseHoverBehavior()
    {
        timer = new DispatcherTimer();
        timer.Interval = TimeSpan.FromSeconds(6);
        timer.Tick += Timer_Tick;
    }

    private static void OnElementChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {            
        var element = (sender as Button);
        target = (UIElement)e.NewValue;
        target.Visibility = Visibility.Hidden;

        element.MouseEnter += Element_MouseEnter;
        target.MouseEnter += Element_MouseEnter;
        element.MouseLeave += Element_MouseLeave;
        target.MouseLeave += Element_MouseLeave;
    }

    private static DispatcherTimer timer;

    private static void Element_MouseLeave(object sender, MouseEventArgs e)
    { 
        timer.Start();
    }

    private static void Timer_Tick(object sender, EventArgs e)
    {
        target.Visibility = Visibility.Hidden;
    }

    private static void Element_MouseEnter(object sender, MouseEventArgs e)
    {            
        timer.Stop();
        target.Visibility = Visibility.Visible;
    }

    public static void SetElement(DependencyObject element, UIElement value)
    {
        element.SetValue(ElementProperty, value);
    }

    public static string GetElement(DependencyObject element)
    {
        return (string)element.GetValue(ElementProperty);
    }
}
在xaml中:


有没有人有更好的办法来有效地做到这一点


谢谢。

正如Chris W.所暗示的,最好的做法是使用
情节提要
s和
EventTrigger
s。这正是他们设计的场景。下面是它如何与您的示例一起工作(我将图像更改为矩形,以便可以轻松地进行测试):


你也可以让图像在5秒后开始淡出,在6秒后完全淡出,等等。我知道这看起来像是很多标记,但它非常灵活,避免了很多编码逻辑方面的麻烦,如果你想做更复杂的事情的话。(事实上,如果您想要更复杂的东西,无论如何都必须使用
情节提要
,并且在代码中执行它们并不比在XAML中更漂亮)


但是,如果出于某种原因您不想使用故事板动画,那么您所做的对于特定场景来说似乎也很好。如果您担心内存泄漏(我不知道这些XAML元素在应用程序的生命周期中会被创建和销毁多少次,但除非它非常严重,否则我不会担心这一点;当
FrameworkElement
卸载时,即使FEs本身没有获得GC,最重要的资源也会被释放),您可以在
OnElementChanged
中订阅那些元素的
卸载的
事件,并在处理这些事件时从
Element\u MouseEnter
Element\u MouseLeave
处理程序中取消订阅它们。

您是否打算在codebehind中执行此操作?我可以向您展示如何使用故事板,但我更熟悉纯xaml的使用方法。@Chris。好的。如果你能以xaml的方式给我,那就太好了。太好了。谢谢你的回答。我可以有故事板。让我试试这个。
<StackPanel>
    <Image Source="steve.jpg" Width="200" x:Name="image"/>
    <Button Width="200" Height="100" Margin="20" local:MouseHoverBehavior.Element="{Binding ElementName=image}"/>
</StackPanel>
   <StackPanel>
        <StackPanel.Triggers>
            <EventTrigger SourceName="_button" RoutedEvent="MouseEnter">
                <BeginStoryboard>
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="image" 
                                                       Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0"
                                                    Value="{x:Static Visibility.Visible}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger SourceName="_button" RoutedEvent="MouseLeave">
                <BeginStoryboard>
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="image"                                                            
                                                       Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0:00:06" 
                                                    Value="{x:Static Visibility.Collapsed}" />
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger SourceName="image" RoutedEvent="MouseEnter">
                <BeginStoryboard>
                    <Storyboard>
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="image" 
                                                       Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0"
                                                    Value="{x:Static Visibility.Visible}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger SourceName="image" RoutedEvent="MouseLeave">
                <BeginStoryboard>
                    <Storyboard Duration="1">
                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="image"                                                            
                                                       Storyboard.TargetProperty="Visibility">
                            <DiscreteObjectKeyFrame KeyTime="0:00:06" 
                                                    Value="{x:Static Visibility.Collapsed}" />
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </StackPanel.Triggers>

        <Button x:Name="_button"
                Width="200" Height="100" Margin="20" />
        <Rectangle Visibility="Collapsed"
                   Width="200" 
                   Height="200"
                   Fill="Yellow"
                   x:Name="image"/>
    </StackPanel>