WPF の RichTextBox に RTF ファイルを読み込ませるテストをしていたら、おかしなことに気付いた。
元々 RTF ファイルに記述してあったハイパーリンクが、RichTextBox に読み込ませると、RichTextBox 上で動作しない。RichTextBox 上でリンクの上にマウスカーソルを動かしても手のマークにならないし、クリックしてもジャンプしない。
Forms の RichTextBox にもいろいろ問題があったけど、WPF の RichTextBox はそれに輪をかけて問題が多いように思う(個人の感想です)。それはともかく、対策を調べてみた。
リンクが動作するようにするには、まず xaml を下記のように修正する。
<RichTextBox Name="body" Margin="10,10,10,50" IsReadOnly="True" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"> <RichTextBox.Resources> <Style TargetType="Hyperlink"> <Setter Property="Cursor" Value="Hand" /> <EventSetter Event="MouseLeftButtonDown" Handler="Hyperlink_MouseLeftButtonDown" /> </Style> </RichTextBox.Resources> </RichTextBox>
次に、ハンドラを用意する。
Private Sub Hyperlink_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Dim hyperlink As Hyperlink = sender Process.Start(hyperlink.NavigateUri.ToString()) End Sub
これで、RichTextBox 内のハイパーリンクが動作するようになる。
なお、「なんでイベントが MouseLeftButtonDown なの?」「Click じゃダメなの?」「MouseLeftButtonUp のほうがいいんじゃないですか?」というごもっともな疑問が出るかもしれない。私もそう思った。
それで Click とか MouseLeftButtonUp に変えてみて、それなりに時間をかけて試してみたのだが、なぜか全く動作しない。
「おっかしーな~(-“-)」と思って、その理由をネット検索して調べてみると、どうやら WPF の RichTextBox でのハイパーリンクは「そういうもの」らしい。MouseLeftButtonDown でないと動作しない。そう決まってるらしい。(説得力のない説明でスンマセン)
ちなみに、TextBlock や Label や NavigationWindow や Frame の中などでは、ネイティブナビゲーションがサポートされているので、上記のように変なことをしないでもちゃんとリンクが動作するらしい。
素直にハイパーリンクを動作させたいならば、WebBrowser コントロールを使うという選択肢もある。私は MouseLeftButtonDown に違和感を感じたので、WebBrowser コントロールを使うことにしましたよっと。
ご存知だと思うが、MouseLeftButtonDown と MouseLeftButtonUp のどちらかを使うかによって、ユーザーに与える影響は小さくないと考える。
たとえば、通常、ユーザーがウィンドウ内の「実行」ボタンを押そうとして、マウスポインタをボタンの上に重ねてマウスの左ボタンをグッと押しこんだとする。
でも、そのボタンから指を離す前にマウスポインタをボタン上からずらして遠ざけてしまえば、「実行」ボタンが押されたことにはならない(確定しない)。このように、「押そうかどうか」を迷ったユーザーには、すんでのところで「やめる」という機会が(通常は)与えられている。
ところがイベントに MouseLeftButtonDown を使ってしまうと、ユーザーからこの最後の「やめる」機会を奪うことになってしまう。左ボタンを押しだだけでは(通常は)確定しないことを知っているユーザーを混乱させてしまうかもしれない。