Ambri
Ambri

Reputation: 47

Hyperlink events are not raised on first click if MousePreviewUp event is subscribed

I have loaded a TextBlock in a ContentControl and added a Hyperlink as an object in the Inlines collection in the TextBlock.

If I subscribe a handler to the ContentControl.PreviewMouseUp event which sets the ContentControl.Foreground property, the RequestNavigate and Click events are not raised the first time the link is clicked. If the link is clicked a second time, the events are raised.

Everything works fine if the event is not subscribed, or the handler does nothing.


Initialization code (in window constructor, after 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);

Event handlers as follows:

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 as follows:

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


Note: if the PreviewMouseUp handler is changed so that it always changes the color (e.g. create a bool that selects between two different colors and is toggled each time the handler is called), the events are never raised. E.g.:

private bool _toggle;

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

Is there any way to have the PreviewMouseUp handler set the color but still have the RequestNavigate and Click events raised when the link is clicked the first time?

Upvotes: 2

Views: 403

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70691

I don't know exactly what's going on here, but it's clear from the symptoms that there's something about changing the ContentControl.Foreground property that interrupts the normal handling of the mouse event. When you set the property value, this causes WPF to decide that the event should be ignore (maybe it treats the property change as an indication that the event has been handled), and so the events which would normally be raised later aren't in fact raised.

Given that, it seems to me that the most obvious work-around is to defer the change in the property value until after mouse event has in fact been completely handled, including raising those events. And the most obvious way I can think of to do that is to use the Dispatcher to invoke the operation later.

I.e. by using Dispatcher.InvokeAsync(), we can ensure that the handling of the mouse event itself is completely processed before the property change is done, because the dispatcher is busy dealing with the mouse event and won't be available to run the invoked delegate until it's finished with the mouse event.

That would look something like this:

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

If you change your PreviewMouseUp handler to the above, you should see that the events are raised even on the first mouse click.

Upvotes: 1

Related Questions