16

I have a WPF RichTextBox with isReadOnly set to True. I would like users to be able to click on HyperLinks contained within the RichTextBox, without them having to hold down Ctrl.

The Click event on the HyperLink doesn't seem to fire unless Ctrl is held-down, so I'm unsure of how to proceed.

David Rönnqvist
  • 55,638
  • 18
  • 162
  • 201
John Noonan
  • 911
  • 3
  • 11
  • 19

6 Answers6

29

I found a solution. Set IsDocumentEnabled to "True" and set IsReadOnly to "True".

<RichTextBox IsReadOnly="True" IsDocumentEnabled="True" />

Once I did this, the mouse would turn into a 'hand' when I hover over a text displayed within a HyperLink tag. Clicking without holding control will fire the 'Click' event.

I am using WPF from .NET 4. I do not know if earlier versions of .NET do not function as I describe above.

JHubbard80
  • 2,147
  • 1
  • 19
  • 23
  • 6
    this has the unforunate side effect of making the text unselectable for copy and paste purposes. – Julien Dec 17 '12 at 15:40
  • To clarify what's going on: The document must be enabled to click on the hyperlink, and it will default to disabled. But if it's not read-only, you have to hold down the control key for it to raise the event, because if you are allowed to edit the text, you don't want to accidentally navigate. This behavior is the same as MS Word when editing a document: in readonly mode you just click the URL, but while editing you have to hold the control key. – Bryce Wagner Aug 22 '19 at 17:53
15

JHubbard80's answer is a possible solution, it's the easiest way if you do not need the content to be selected.

However I need that :P here is my approach: set a style for the Hyperlinks inside the RichTextBox. The essential is to use a EventSetter to make the Hyperlinks handling the MouseLeftButtonDown event.

<RichTextBox>
    <RichTextBox.Resources>
        <Style TargetType="Hyperlink">
            <Setter Property="Cursor" Value="Hand" />
            <EventSetter Event="MouseLeftButtonDown" Handler="Hyperlink_MouseLeftButtonDown" />
        </Style>
    </RichTextBox.Resources>
</RichTextBox>

And in codebehind:

private void Hyperlink_MouseLeftButtonDown(object sender, MouseEventArgs e)
{
    var hyperlink = (Hyperlink)sender;
    Process.Start(hyperlink.NavigateUri.ToString());
}

Thanks to gcores for the inspiaration.

Community
  • 1
  • 1
hillin
  • 1,411
  • 14
  • 20
  • I don't get the hand, but whatever. It works, and even better, gives me access to the hyperlink's navigation code - so if a directory doesn't exist, my app doesn't crash! – Darkhydro Nov 12 '14 at 00:22
  • Handling the click event worked for me. It might be a Windows 10 / WPF 4.5 thing but it worked. Thanks. – CAD bloke Apr 18 '16 at 10:17
5

Managed to find a way around this, pretty much by accident.

The content that's loaded into my RichTextBox is just stored (or inputted) as a plain string. I have subclassed the RichTextBox to allow binding against it's Document property.

What's relevant to the question, is that I have an IValueConverter Convert() overload that looks something like this (code non-essential to the solution has been stripped out):

FlowDocument doc = new FlowDocument();
Paragraph graph = new Paragraph();

Hyperlink textLink = new Hyperlink(new Run(textSplit));
textLink.NavigateUri = new Uri(textSplit);
textLink.RequestNavigate += 
  new System.Windows.Navigation.RequestNavigateEventHandler(navHandler);

graph.Inlines.Add(textLink);
graph.Inlines.Add(new Run(nonLinkStrings));

doc.Blocks.Add(graph);

return doc;

This gets me the behavior I want (shoving plain strings into RichTextBox and getting formatting) and it also results in links that behave like a normal link, rather than one that's embedded in a Word document.

John Noonan
  • 911
  • 3
  • 11
  • 19
0

I changed EventSetter from @hillin's answer. MouseLeftButtonDown didn't work in my code (.Net framework 4.5.2).

<EventSetter Event="RequestNavigate" Handler="Hyperlink_RequestNavigate" />
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
{
    Process.Start(e.Uri.ToString());
}
choi
  • 9
  • 2
0

Do not handle any mouse events explicitly and do not force the cursor explicitly - like suggested in every answer.

It's also not required to make the complete RichTextBox read-only like (as suggested in another answer).

To make the Hyperlink clickable without pressing the Ctrl key, the Hyperlink must be made read-only e.g., by wrapping it into a TextBlock or by making the complete RichTextBox read-only (by setting RichTextBox.IsReadOnly to false).
Then simply handle the Hyperlink.RequestNavigate event or/and attach an ICommand to the Hyperlink.Command property:

<RichTextBox IsDocumentEnabled="True">
  <FlowDocument>
    <Paragraph>
      <Run Text="Some editable text" />

      <TextBlock>                
        <Hyperlink NavigateUri="https://duckduckgo.com"
                   RequestNavigate="OnHyperlinkRequestNavigate">
          DuckDuckGo
        </Hyperlink>
      </TextBlock>
    </Paragraph>
  </FlowDocument>
</RichTextBox>
BionicCode
  • 19,599
  • 2
  • 21
  • 37
-1

If you want to turn Arrow into a Hand cursor always without default system navigation, below is the approach.

<RichTextBox>
            <RichTextBox.Resources>
                <Style TargetType="{x:Type Hyperlink}">                                
                    <EventSetter Event="MouseEnter" Handler="Hyperlink_OnMouseEnter"/>
                </Style>                
            </RichTextBox.Resources>
</RichTextBox>


private void Hyperlink_OnMouseEnter(object sender, MouseEventArgs e)
        {
            var hyperlink = (Hyperlink)sender;
            hyperlink.ForceCursor = true;
            hyperlink.Cursor = Cursors.Hand;
        }
AZ_
  • 36,879
  • 28
  • 155
  • 201