使用依赖属性在n秒后隐藏元素的可见性

使用依赖属性在n秒后隐藏元素的可见性

问题描述:

我的目标:我有一个Button和一个ImageImage默认为Hidden,一旦用户将鼠标悬停在Button上,应显示Image。它应该是可见的,直到用户将鼠标悬停在ImageButton上。它应该在用户离开鼠标点6秒后(隐藏按钮或图像)隐藏图像。鼠标在6秒前悬停,离开时应重新启动计时器。使用依赖属性在n秒后隐藏元素的可见性

我试过我已经有一个可行的解决方案,使用AttachedProperty但这不是有效的。我感觉这里会有内存泄漏,因为这里有static

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:

<StackPanel> 
    <Image Source="steve.jpg" Width="200" x:Name="image"/> 
    <Button Width="200" Height="100" Margin="20" local:MouseHoverBehavior.Element="{Binding ElementName=image}"/> 
</StackPanel> 

没有人在有效的方式这样做的更好的主意。

谢谢。

+2

你是否在代码隐藏方面做了设置?我可以告诉你如何与故事板,但纯XAML是更熟悉我如何做到这一点。 –

+0

@Chris。 。是的,请。如果你只能以xaml的方式给我,这将是非常好的。 – Gopichandar

正如Chris W.所暗示的那样,最佳做法是使用Storyboard s和EventTrigger s。这正是他们设计的场景。下面是它如何与你的榜样工作(我改变了图像的矩形,所以我可以很容易地测试它):

<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> 

你也可以有6等后的图像淡出开始5秒后,完全我知道它看起来像很多标记,但它非常灵活,并且避免了许多编码逻辑头痛,如果你想做更复杂的事情,你会经历的。 (事实上​​,如果你想要更复杂的东西,那么你必须使用Storyboard,并且在代码中执行操作并不比XAML更漂亮)。

但是,如果您不想使用故事板动画出于某种原因,那么对于您的特定场景,您所做的事情似乎也很好。如果您担心内存泄漏(我不知道这些XAML元素在应用程序的整个生命周期中会创建和销毁多少次,但除非有很多我不担心这个;最重要的是资源在FrameworkElement被卸载时释放,即使FE本身没有得到GC'd),您可以在您的OnElementChanged订阅这些元素的“Unloaded”事件,并在处理这些事件时从您的Element_MouseEnterElement_MouseLeave处理程序取消订阅它们。

+0

太好了。感谢您的回答。我可以有故事板。让我试试这个。 – Gopichandar