WPF鼠标移出控件范围,导致鼠标事件无法触发的解决方法

 1 <Window x:Class="WpfApp6.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:WpfApp6"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="100" Width="200">
 9     <Grid>
10         <TextBlock x:Name="lblTest" Text="Test" HorizontalAlignment="Center" VerticalAlignment="Center" MouseDown="lblTest_MouseDown" MouseUp="lblTest_MouseUp"/>
11     </Grid>
12 </Window>
 1 using System.Windows;
 2 using System.Windows.Input;
 3 using System.Windows.Media;
 4 
 5 namespace WpfApp6
 6 {
 7     /// <summary>
 8     /// MainWindow.xaml 的交互逻辑
 9     /// </summary>
10     public partial class MainWindow : Window
11     {
12         public MainWindow()
13         {
14             InitializeComponent();
15         }
16 
17         private void lblTest_MouseDown(object sender, MouseButtonEventArgs e)
18         {
19             lblTest.Background = Brushes.Green;
20         }
21 
22         private void lblTest_MouseUp(object sender, MouseButtonEventArgs e)
23         {
24             lblTest.Background = Brushes.Red;
25         }
26     }
27 }

需求场景:如上述代码,窗口一个TextBlock,鼠标在该控件上按下时,背景色置为Green,鼠标释放时,背景色置为Red。

问题场景:当鼠标在TextBlock上按下时,背景色按照预想中的置为了Green,但当鼠标移动到TextBlock外的范围在释放鼠标时,MouseUp事件没有被触发。

问题原因:当鼠标在TextBlock上时,此时鼠标被TextBlock控件捕获,所以释放鼠标时可以按照预想将背景色置为Red的;但当鼠标没有在TextBlock上而是在其他地方即Window上时,TextBlock控件丢失了鼠标捕获,而是被Window捕获,所以鼠标释放时,也就不会触发TextBlock的MouseUp事件,应该是会触发Window的MouseUp事件;

解决办法:

第一步:使用Mouse.Capture()设置鼠标捕获,当一个鼠标捕获被设置到一个元素时,鼠标就只能与该元素进行交互,无法与其他元素进行交互,将代码修改为如下所示:

 1 using System.Windows;
 2 using System.Windows.Input;
 3 using System.Windows.Media;
 4 
 5 namespace WpfApp6
 6 {
 7     /// <summary>
 8     /// MainWindow.xaml 的交互逻辑
 9     /// </summary>
10     public partial class MainWindow : Window
11     {
12         public MainWindow()
13         {
14             InitializeComponent();
15         }
16 
17         private void lblTest_MouseDown(object sender, MouseButtonEventArgs e)
18         {
19             lblTest.Background = Brushes.Green;
20             if (sender is IInputElement ele)
21             {
22                 // 将鼠标捕获到触发该事件的元素
23                 Mouse.Capture(ele);
24             }
25         }
26 
27         private void lblTest_MouseUp(object sender, MouseButtonEventArgs e)
28         {
29             lblTest.Background = Brushes.Red;
30             Mouse.Capture(null);// 重置鼠标捕获
31         }
32     }
33 }

在MouseDown事件中,通过Mouse.Capture()将鼠标捕获到了TextBlock控件上,当我们鼠标在任意位置释放鼠标,即使没有鼠标没有在TextBlock上,也会触发TextBlock的MouseUp事件,因为我们设置了TextBlock鼠标捕获。

在MouseUp事件中我们需要通过传入null参数,重置鼠标捕获,否则会导致鼠标的所有交互都指向TextBlock,而无法与其他控件进行交互。

到这里貌似我们的需求可以得到满足了,但是,还有一些情况下会导致系统丢失鼠标捕获,即使使用了Mouse.Capture(),任然无法正常进入MouseUp事件。

代码修改如下:

 1 using System.Windows;
 2 using System.Windows.Input;
 3 using System.Windows.Media;
 4 
 5 namespace WpfApp6
 6 {
 7     /// <summary>
 8     /// MainWindow.xaml 的交互逻辑
 9     /// </summary>
10     public partial class MainWindow : Window
11     {
12         public MainWindow()
13         {
14             InitializeComponent();
15         }
16 
17         private void lblTest_MouseDown(object sender, MouseButtonEventArgs e)
18         {
19             lblTest.Background = Brushes.Green;
20             if (sender is IInputElement ele)
21             {
22                 // 将鼠标捕获到触发该事件的元素
23                 Mouse.Capture(ele);
24             }
25             MessageBox.Show("MouseDown");
26         }
27 
28         private void lblTest_MouseUp(object sender, MouseButtonEventArgs e)
29         {
30             lblTest.Background = Brushes.Red;
31             Mouse.Capture(null);// 重置鼠标捕获
32         }
33     }
34 }

如上代码,虽然在MouseDown事件中通过Mouse.Capture()设置了鼠标捕获,但当MouseDown事件中弹出系统对话框时,此时会导致鼠标捕获丢失,从而导致MouseUp事件无法触发。

第二步:使用UIElement类中提供的GotMouseCapture和LostMouseCapture事件,监听元素获取/释放鼠标捕获。

代码修改如下:

 1 <Window x:Class="WpfApp6.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:WpfApp6"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="100" Width="200">
 9     <Grid>
10         <TextBlock x:Name="lblTest" Text="Test" HorizontalAlignment="Center" VerticalAlignment="Center" MouseDown="lblTest_MouseDown" MouseUp="lblTest_MouseUp" UIElement.GotMouseCapture="lblTest_GotMouseCapture" UIElement.LostMouseCapture="lblTest_LostMouseCapture"/>
11     </Grid>
12 </Window>
 1 using System.Windows;
 2 using System.Windows.Input;
 3 using System.Windows.Media;
 4 
 5 namespace WpfApp6
 6 {
 7     /// <summary>
 8     /// MainWindow.xaml 的交互逻辑
 9     /// </summary>
10     public partial class MainWindow : Window
11     {
12         public MainWindow()
13         {
14             InitializeComponent();
15         }
16 
17         private void lblTest_MouseDown(object sender, MouseButtonEventArgs e)
18         {
19             if (sender is IInputElement ele)
20             {
21                 // 将鼠标捕获到触发该事件的元素
22                 Mouse.Capture(ele);
23             }
24             MessageBox.Show("MouseDown");
25         }
26 
27         private void lblTest_MouseUp(object sender, MouseButtonEventArgs e)
28         {
29             Mouse.Capture(null);// 重置鼠标捕获
30         }
31 
32         private void lblTest_GotMouseCapture(object sender, MouseEventArgs e)
33         {
34             lblTest.Background = Brushes.Green;
35         }
36 
37         private void lblTest_LostMouseCapture(object sender, MouseEventArgs e)
38         {
39             lblTest.Background = Brushes.Red;
40         }
41     }
42 }

至此,问题解决!

 

posted @ 2022-04-28 14:40  CS讷于言而敏于行  阅读(1267)  评论(0编辑  收藏  举报