Reputation: 47
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
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