尽管光标没有超过按钮,为什么IsMouseOver触发器不起作用?

时间:2016-09-17 13:40:36

标签: wpf triggers ismouseover

我有一个简单的例子来说明这个问题。有两个IsMouseOver,其中一个是 MainWindow ,另一个是 SecondWindow 。我在底部的 SecondWindow 中放了一个大按钮,按钮有一个<Window x:Class="WpfApplication3.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" AllowsTransparency="True" WindowStyle="None"> <Grid> <Button Content="Show Dialog" HorizontalAlignment="Left" Margin="10,71,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" RenderTransformOrigin="-1.211,0.918"/> </Grid> 触发器。但是当光标移动时它无法正常工作。我使用下面的代码来创建整个示例。尝试一下,看看问题。我该如何解决?

MainWindow.xaml

<Window x:Class="WpfApplication3.SecondWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    Background="Green" AllowsTransparency="True" WindowStyle="None">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
    </Grid.RowDefinitions>

    <Button Content="SAVE" Height="50" VerticalAlignment="Bottom">
        <Button.Style>
            <Style TargetType="Button">
                <Setter Property="Background" Value="Blue"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="Button">
                            <Border Background="{TemplateBinding Background}">
                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Background" Value="Red"/>
                                    <Setter Property="Foreground" Value="White"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Button.Style>
    </Button>
</Grid>

SecondWindow.xaml

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        SecondWindow w = new SecondWindow();
        w.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
        w.Owner = this;
        w.ShowDialog();
    }
}

MainWindow.cs

getTime

问题图片:光标在MainWindow上,而不是SecondWindow,但按钮的背景颜色不会变为蓝色,它仍然是红色。

enter image description here

1 个答案:

答案 0 :(得分:1)

这是一个非常大的挑战,因为看起来AllowTransparency =&#34; True&#34;禁用与底层窗口等相关的鼠标的所有正常行为。

作为一种解决方法,我尝试使用Button的子类来执行此操作,如下所示:

按钮类:

using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace SO39547486
{
  public class MagicButton : Button, IDisposable
  {
    System.Timers.Timer m_colorTimer;
    DateTime m_lastMouseMove;
    Brush m_tmpBackground;
    Brush m_tmpForeground;

    public MagicButton()
    {
      MouseMove += MagicButton_MouseMove;
    }

    ~MagicButton()
    {
      Dispose();
    }

    public Brush FocusBackground
    {
      get { return (Brush)GetValue(FocusBackgroundProperty); }
      set { SetValue(FocusBackgroundProperty, value); }
    }

    // Using a DependencyProperty as the backing store for FocusBackground.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FocusBackgroundProperty =
        DependencyProperty.Register("FocusBackground", typeof(Brush), typeof(MagicButton), new PropertyMetadata(Brushes.Magenta));

    public Brush FocusForeground
    {
      get { return (Brush)GetValue(FocusForegroundProperty); }
      set { SetValue(FocusForegroundProperty, value); }
    }

    // Using a DependencyProperty as the backing store for FocusForeground.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FocusForegroundProperty =
        DependencyProperty.Register("FocusForeground", typeof(Brush), typeof(MagicButton), new PropertyMetadata(Brushes.White));


    private void CleanupTimer()
    {
      if (m_colorTimer != null)
      {
        m_colorTimer.Stop();
        m_colorTimer.Dispose();
        m_colorTimer = null;
      }
    }

    public void Dispose()
    {
      CleanupTimer();
    }

    private void MagicButton_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
    {
      if (m_colorTimer == null)
      {
        m_colorTimer = new System.Timers.Timer(50);
        m_colorTimer.Elapsed += ColorTimer_Elapsed;
        m_colorTimer.Start();
        m_tmpBackground = Background;
        Background = FocusBackground;
        m_tmpForeground = Foreground;
        Foreground = FocusForeground;
      }

      var point = e.GetPosition(this);
      m_lastMouseMove = DateTime.Now;
    }

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool GetCursorPos(ref Win32Point pt);

    [StructLayout(LayoutKind.Sequential)]
    private struct Win32Point
    {
      public Int32 X;
      public Int32 Y;
    };
    private static Point GetMousePosition()
    {
      Win32Point w32Mouse = new Win32Point();
      GetCursorPos(ref w32Mouse);
      return new Point(w32Mouse.X, w32Mouse.Y);
    }

    private bool IsCursorOverMe()
    {
      var cursorPos = GetMousePosition();
      var topLeft = PointToScreen(new Point(0, 0));
      Rect bounds = new Rect(topLeft.X, topLeft.Y, ActualWidth, ActualHeight);
      return bounds.Contains(cursorPos);
    }

    private void ColorTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
      if (m_colorTimer != null)
      {
        var duration = DateTime.Now - m_lastMouseMove;
        if (duration.TotalMilliseconds < 100)
        {
          Dispatcher.Invoke(() => 
          {
            if (!IsCursorOverMe())
            {
              Background = m_tmpBackground;
              Foreground = m_tmpForeground;
              CleanupTimer();
            }
          });          
        }
      }
    }
  }
}

相应的XAML如下所示:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="SO39547486.SecondWindow"
  xmlns:local="clr-namespace:SO39547486"
    Title="Window1" Height="300" Width="300"    
    Background="Green" AllowsTransparency="True" WindowStyle="None">
  <Grid>
    <local:MagicButton 
      Content="SAVE" 
      x:Name="SaveCmd" 
      Height="50" 
      VerticalAlignment="Bottom"
      FocusBackground="Red"
      FocusForeground="White"
      >
      <Button.Style>
        <Style TargetType="{x:Type Button}">
          <Setter Property="Background" Value="Blue"/>
        </Style>
      </Button.Style>
      <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
          <Border Background="{TemplateBinding Background}" UseLayoutRounding="True" d:DesignUseLayoutRounding="True">
            <ContentPresenter 
              ContentTemplate="{TemplateBinding ContentTemplate}" 
              Content="{TemplateBinding Content}" 
              ContentStringFormat="{TemplateBinding ContentStringFormat}" 
              HorizontalAlignment="Center" 
              UseLayoutRounding="True" 
              VerticalAlignment="Center" 
              d:DesignUseLayoutRounding="True"/>
          </Border>
        </ControlTemplate>
      </Button.Template>
    </local:MagicButton>
  </Grid>
</Window>

对于如此小的结果,这是一个相当大的工作方式。至少它可以在我的电脑上运行,所以我希望它也适合你。

相关问题