2016-09-16 4 views
0

Моя цель: У меня есть Button и Image. Image будет Hidden по умолчанию и как только пользователь Наведите указатель мыши на Button, Image должен быть показан. Он должен быть видимым, пока пользователь не опустит мышь над Image или Button. Он должен скрывать изображение через 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

@ Крис. , Да, пожалуйста. Это будет действительно здорово, если вы можете дать мне только в xaml. – Gopichandar

ответ

2

Как сообщил Крис У., наилучшей практикой было бы использовать 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> 

Вы также можете иметь образ исчезать, начиная через 5 секунд, полностью после 6 и т.д. Я знаю, что это похоже на большую разметку, но она очень гибкая и позволяет избежать многих логических ошибок в кодировании, которые вы пройдете, если хотите сделать что-то более сложное. (На самом деле, если вам нужно что-то более сложное, вам все равно придется использовать Storyboard, а делать их в коде не особенно красивее, чем в XAML).

Но если вы не хотите использовать анимацию раскадровки по какой-то причине, то, что вы делаете, кажется слишком хорошим для вашего конкретного сценария. Если вас беспокоит утечка памяти (я не знаю, сколько раз эти элементы XAML будут созданы и уничтожены в течение всего срока действия приложения, но если это не так много, я бы не стал беспокоиться об этом; ресурсы освобождаются, когда FrameworkElement выгружаются, даже если сами FE не получают GC'd), вы можете в своем OnElementChanged подписаться на события этих элементов Unloaded и при обработке этих событий отказаться от подписки на них от ваших обработчиков и Element_MouseLeave.

+0

Отлично. Спасибо за Ваш ответ. У меня все в порядке, есть раскадровки. Позвольте мне попробовать. – Gopichandar

Смежные вопросы