Why IsMouseOver is recognized and MouseDown isn't (Wpf Style trigger)?

21,549

Solution 1

Well, I guess you are mistaking MouseDown event for property. There is no IsMouseDown property but there exist similar IsPressed property but only for classes inheriting ButtonBase. You should just use event in code-behind or write an attached property if you want to keep your code-behind clean.

This is how you do it. Create class:

using System;
using System.Windows;

namespace Mrpyo
{
    public static class MouseDownHelper 
    {
        public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.RegisterAttached("IsEnabled", 
        typeof(bool), typeof(MouseDownHelper), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnNotifyPropertyChanged)));

        public static void SetIsEnabled(UIElement element, bool value)
        {
            element.SetValue(IsEnabledProperty, value);
        }

        public static bool GetIsEnabled(UIElement element)
        {
            return (bool)element.GetValue(IsEnabledProperty);
        }

        private static void OnNotifyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var element = d as UIElement;
            if (element != null && e.NewValue != null)
            {
                if ((bool)e.NewValue)
                {
                    Register(element);
                }
                else
                {
                    UnRegister(element);
                }
            } 
        }

        private static void Register(UIElement element)
        {
            element.PreviewMouseDown += element_MouseDown;
            element.PreviewMouseLeftButtonDown += element_MouseLeftButtonDown;
            element.MouseLeave += element_MouseLeave;
            element.PreviewMouseUp += element_MouseUp;
        }

        private static void UnRegister(UIElement element)
        {
            element.PreviewMouseDown -= element_MouseDown;
            element.PreviewMouseLeftButtonDown -= element_MouseLeftButtonDown;
            element.MouseLeave -= element_MouseLeave;
            element.PreviewMouseUp -= element_MouseUp;
        }

        private static void element_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var element = sender as UIElement;
            if (element != null)
            {
                SetIsMouseDown(element, true);
            }
        }

        private static void element_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var element = sender as UIElement;
            if (element != null)
            {
                SetIsMouseLeftButtonDown(element, true);
            }
        }

        private static void element_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            var element = sender as UIElement;
            if (element != null)
            {
                SetIsMouseDown(element, false);
                SetIsMouseLeftButtonDown(element, false);
            }
        }

        private static void element_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            var element = sender as UIElement;
            if (element != null)
            {
                SetIsMouseDown(element, false);
                SetIsMouseLeftButtonDown(element, false);
            }
        }

        internal static readonly DependencyPropertyKey IsMouseDownPropertyKey = DependencyProperty.RegisterAttachedReadOnly("IsMouseDown",
        typeof(bool), typeof(MouseDownHelper), new FrameworkPropertyMetadata(false));
        public static readonly DependencyProperty IsMouseDownProperty = IsMouseDownPropertyKey.DependencyProperty;

        internal static void SetIsMouseDown(UIElement element, bool value)
        {
            element.SetValue(IsMouseDownPropertyKey, value);
        }

        public static bool GetIsMouseDown(UIElement element)
        {
            return (bool)element.GetValue(IsMouseDownProperty);
        }

        internal static readonly DependencyPropertyKey IsMouseLeftButtonDownPropertyKey = DependencyProperty.RegisterAttachedReadOnly("IsMouseLeftButtonDown",
        typeof(bool), typeof(MouseDownHelper), new FrameworkPropertyMetadata(false));
        public static readonly DependencyProperty IsMouseLeftButtonDownProperty = IsMouseLeftButtonDownPropertyKey.DependencyProperty;

        internal static void SetIsMouseLeftButtonDown(UIElement element, bool value)
        {
            element.SetValue(IsMouseLeftButtonDownPropertyKey, value);
        }

        public static bool GetIsMouseLeftButtonDown(UIElement element)
        {
            return (bool)element.GetValue(IsMouseLeftButtonDownProperty);
        }
    }
}

Then in your style:

<Setter Property="local:MouseDownHelper.IsEnabled" Value="True"/>
<Style.Triggers>
    <Trigger Property="local:MouseDownHelper.IsMouseLeftButtonDown" Value="True">
        <!-- ... -->
    </Trigger>
</Style.Triggers>

And of course add namespace in your XAML file (look at the top):

xmlns:local="clr-namespace:Mrpyo"

Solution 2

You can use MouseDown Event in Style.Triggers but you have to use an EventTrigger for that.

<EventTrigger RoutedEvent="MouseEnter">
    <BeginStoryboard>
        <Storyboard>
            ...
        </Storyboard>
    </BeginStoryboard>
</EventTrigger>

And remember that

the action will not be undone once the condition that raised the event is no longer true.

Solution 3

You could use PreviewMouseLeftButtonDown when using Control.Triggers, replacing control with the control item the template is being used in:

<Grid>
  <Grid.Triggers>
    <EventTrigger RoutedEvent="Grid.PreviewMouseLeftButtonDown">
      <BeginStoryboard>
        <Storyboard>
          ...
        </Storyboard>
      </BeginStoryboard>
    </EventTrigger>
  </Grid.Triggers>
</Grid>
Share:
21,549
Erre Efe
Author by

Erre Efe

"When you're doing something you're passionate about, stress becomes a feature not a bug."

Updated on July 05, 2022

Comments

  • Erre Efe
    Erre Efe almost 2 years

    Why IsMouseOver is recognized as a WPF style trigger and MouseDown isn't -given that both are valid UIElement properties as seen here-. First trigger works well but second one doesn't even compile.

    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="true">
            <Setter Property="OpacityMask">
                <Setter.Value>
                    <LinearGradientBrush >
                        <GradientStop Color="Transparent" Offset="0"/>
                        <GradientStop Color="Black" Offset="0.5"/>
                        <GradientStop Color="Transparent" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Trigger>
        <Trigger Property="MouseDown" Value="true">
            <Setter Property="OpacityMask">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Color="Black" Offset="0" />
                        <GradientStop Color="White" Offset="1" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Trigger>
    </Style.Triggers>