在不按住 CTRL 的情况下单击 RichTextBox 中的超链接 - WPF

发布于 2024-07-18 08:09:03 字数 197 浏览 5 评论 0原文

我有一个 WPF RichTextBox,其 isReadOnly 设置为 True。 我希望用户能够单击 RichTextBox 中包含的超链接,而无需按住 Ctrl

除非按住 Ctrl,否则超链接上的 Click 事件似乎不会触发,因此我不确定如何继续。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

明媚如初 2024-07-25 08:09:04

不要显式处理任何鼠标事件,也不要显式强制光标 - 就像每个答案中所建议的那样。

也不需要将完整的 RichTextBox 设为只读(如另一个答案中所建议的)。

要使Hyperlink在不按Ctrl键的情况下可点击,必须将Hyperlink设置为只读,例如,将其包装到 TextBlock 中(当然,也可以将完整的 RichTextBox 设为只读)。
然后只需处理 Hyperlink.RequestNavigate 事件或/并将 ICommand 附加到 Hyperlink.Command 属性:

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

      <TextBlock>                
        <Hyperlink NavigateUri="https://duckduckgo.com"
                   RequestNavigate="OnHyperlinkRequestNavigate">
          DuckDuckGo
        </Hyperlink>
      </TextBlock>
    </Paragraph>
  </FlowDocument>
</RichTextBox>

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 (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 alternatively by making the complete RichTextBox read-only, of course).
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>
随波逐流 2024-07-25 08:09:04

如果您想将箭头变成手形光标,并且始终没有默认系统导航,请使用以下方法。

<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;
        }

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;
        }
鱼忆七猫命九 2024-07-25 08:09:03

我找到了解决方案。 将 IsDocumentEnabled 设置为“True”并将 IsReadOnly 设置为“True”。

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

完成此操作后,当我将鼠标悬停在超链接标记中显示的文本上时,鼠标将变成“手”。 在不按住控件的情况下单击将触发“Click”事件。

我正在使用 .NET 4 中的 WPF。我不知道早期版本的 .NET 是否无法按照我上面描述的方式运行。

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.

被翻牌 2024-07-25 08:09:03

JHubbard80的答案是一个可能的解决方案,如果您不需要选择内容,这是最简单的方法。

但是我需要:P 这是我的方法:为 RichTextBox 内的 Hyperlink 设置样式。 本质是使用 EventSetter 使 Hyperlink 处理 MouseLeftButtonDown 事件。

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

在代码隐藏中:

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

感谢 gcores 的启发。

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.

落在眉间の轻吻 2024-07-25 08:09:03

几乎是偶然地,设法找到了解决这个问题的方法。

加载到 RichTextBox 中的内容只是作为纯字符串存储(或输入)。 我已经对 RichTextBox 进行了子类化,以允许绑定它的 Document 属性。

与问题相关的是,我有一个 IValueConverter Convert() 重载,看起来像这样(对解决方案来说非必要的代码已被删除):

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;

这让我得到了我想要的行为(将纯字符串推入 RichTextBox 并获取格式),并且它还会导致链接的行为类似于普通链接,而不是嵌入到 Word 文档中的链接。

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.

我乃一代侩神 2024-07-25 08:09:03

我从 @hillin 的答案中更改了 EventSetter。
MouseLeftButtonDown 在我的代码(.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());
}

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());
}
木槿暧夏七纪年 2024-07-25 08:09:03

我的答案基于 @BionicCode 的答案,我想用事件处理程序代码来扩展它,但我在让它工作时遇到了一些困难。

<RichTextBox IsDocumentEnabled="True" IsReadOnly="True">
  <FlowDocument>
    <Paragraph>
      <Run Text="Some editable text" />
      <Hyperlink x:Name="DuckduckgoHyperlink" 
        NavigateUri="https://duckduckgo.com">
        DuckDuckGo
      </Hyperlink>
    </Paragraph>
  </FlowDocument>
</RichTextBox>

我稍微改变了他的代码:

  1. 我希望 RichTextBox 是只读的。 当RichTextBox 为只读时,无需将HyperLink 放入TextBlock 中。 但是,在用户可以进行更改的 RichTextBlock 中使用 TextBlock 是一个很好的建议。
  2. 在我的编程风格中,与代码相关的内容属于代码隐藏文件。 事件处理程序是代码,我什至更喜欢从代码后面将事件处理程序添加到其控件中。 为此,为超链接命名就足够了。

代码隐藏

我需要在 HelpWindow 中显示一些带有链接的富文本:

public HelpWindow() {
  InitializeComponent();

  DuckduckgoHyperlink.RequestNavigate += Hyperlink_RequestNavigate;
}


private void Hyperlink_RequestNavigate(object sender, 
  RequestNavigateEventArgs e) 
{
  Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) {
    UseShellExecute = true,
  });
  e.Handled = true;
}

请注意,任何 HyperLink 都可以使用相同的事件处理程序。 另一种解决方案是不在 XAML 中定义 URL,而是在事件处理程序中对其进行硬编码,在这种情况下,每个 HyperLink 都需要自己的事件处理程序。

在各种 Stackoverflow 答案中,我看到了代码:

Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));

这导致了错误消息:

System.ComponentModel.Win32Exception: '尝试启动进程 'https://duckduckgo.com/' 时发生错误目录“...\bin\Debug\net6.0-windows”。 该系统找不到指定的文件。'

My answer is based on @BionicCode's answer, which I wanted to extend with the event handler code, which I had some difficulties to get it working.

<RichTextBox IsDocumentEnabled="True" IsReadOnly="True">
  <FlowDocument>
    <Paragraph>
      <Run Text="Some editable text" />
      <Hyperlink x:Name="DuckduckgoHyperlink" 
        NavigateUri="https://duckduckgo.com">
        DuckDuckGo
      </Hyperlink>
    </Paragraph>
  </FlowDocument>
</RichTextBox>

I changed his code slightly:

  1. I wanted the RichTextBox to be readonly. When the RichTextBox is readonly, it is not necessary to put the HyperLink into a TextBlock. However, using TextBlock in a RichTextBlock where the user can make changes is a great suggestion.
  2. In my programming style, code related stuff belongs in the code behind file. Event handlers are code and I prefer to even add the event handler to its control from code behind. To do that, it is enough to give the Hyperlink a name.

Code behind

I needed to display some rich text with links in a HelpWindow:

public HelpWindow() {
  InitializeComponent();

  DuckduckgoHyperlink.RequestNavigate += Hyperlink_RequestNavigate;
}


private void Hyperlink_RequestNavigate(object sender, 
  RequestNavigateEventArgs e) 
{
  Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri) {
    UseShellExecute = true,
  });
  e.Handled = true;
}

Note that the same event handler can be used by any HyperLink. Another solution would be not to define the URL in XAML but hard code it in the event handler, in which case each HyperLink needs its own event handler.

In various Stackoverflow answers I have seen the code:

Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));

Which resulted in the error message:

System.ComponentModel.Win32Exception: 'An error occurred trying to start process 'https://duckduckgo.com/' with working directory '...\bin\Debug\net6.0-windows'. The system cannot find the file specified.'

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文