如果MousePreviewUp事件已订阅,则第一次单击时不会引发超链接事件

本文关键字:事件 超链接 单击 MousePreviewUp 如果 第一次 | 更新日期: 2023-09-27 18:20:52

我在ContentControl中加载了一个TextBlock,并在TextBlockInlines集合中添加了一个作为对象的Hyperlink

如果我为设置ContentControl.Foreground属性的ContentControl.PreviewMouseUp事件订阅了一个处理程序,则第一次单击链接时不会引发RequestNavigateClick事件。如果再次单击链接,则会引发事件。

如果事件没有被订阅,或者处理程序什么都不做,那么一切都会正常工作。


初始化代码(在窗口构造函数中,InitializeComponent()之后):

var run = new Run("Google");
Hyperlink hyperlink = new Hyperlink(run);
hyperlink.Click += hyperlink_Click;
hyperlink.RequestNavigate += hyper_RequestNavigate;
hyperlink.NavigateUri = new Uri("http://www.google.com");
textBlock.Inlines.Clear();
textBlock.Inlines.Add(hyperlink);

事件处理程序如下:

private void hyper_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
    System.Diagnostics.Process.Start(e.Uri.ToString());
}
void contentControl_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    contentControl.Foreground = Brushes.Green;
}
void hyperlink_Click(object sender, RoutedEventArgs e)
{
}

XAML如下:

<Grid>
    <ContentControl Name="contentControl">
        <TextBlock Name="textBlock"
                   Width="200"
                   Height="30" />
    </ContentControl>
</Grid>


注意:如果更改了PreviewMouseUp处理程序,使其始终更改颜色(例如,创建一个在两种不同颜色之间进行选择的bool,并在每次调用处理程序时进行切换),则永远不会引发事件。例如:

private bool _toggle;
void contentControl_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    contentControl.Foreground = _toggle ? Brushes.Red : Brushes.Green;
    _toggle = !_toggle;
}

有没有办法让PreviewMouseUp处理程序设置颜色,但在第一次单击链接时仍然引发RequestNavigateClick事件?

如果MousePreviewUp事件已订阅,则第一次单击时不会引发超链接事件

我不知道这里到底发生了什么,但从症状中可以清楚地看出,更改ContentControl.Foreground属性会中断鼠标事件的正常处理。当您设置属性值时,这会导致WPF决定应该忽略该事件(也许它会将属性更改视为事件已被处理的指示),因此通常稍后会引发的事件实际上并没有引发。

鉴于此,在我看来,最明显的解决方法是将属性值的更改推迟到鼠标事件实际上已经完全处理之后,包括引发这些事件。我能想到的最明显的方法是稍后使用Dispatcher调用操作。

也就是说,通过使用Dispatcher.InvokeAsync(),我们可以确保在属性更改之前完全处理鼠标事件本身,因为调度器正忙于处理鼠标事件,并且在完成鼠标事件之前无法运行调用的委托。

看起来像这样:

void contentControl_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    Dispatcher.InvokeAsync(() =>
    {
        contentControl.Foreground = Brushes.Green;
    });
}

如果您将PreviewMouseUp处理程序更改为上面的处理程序,您应该看到即使在第一次单击鼠标时也会引发事件。