動手寫一個簡單的訊息對話方塊一文介紹瞭如何實現滿足常見應用場景的訊息對話方塊。但是內容區域的文字僅僅起到資訊展示作用,對於需要部分關鍵字高亮,或者部分內容有互動性的場景(例如下圖提示資訊中的“what's the risk?”需要跳轉)則無能為力了。本文將介紹如何在WPF中靈活的實現訊息對話方塊中區域性文字內容高亮或者支援跳轉。
HtmlTextBlock的使用
在WPF中,可以採用<Run>
或者TextEffect
實現文字中部分關鍵字高亮,但無法同時滿足部分內容支援連結跳轉功能 。如果能直接使用HTML,問題就迎刃而解了,但是在訊息對話方塊的內容區域放一個webbrowser或cef瀏覽器有點太臃腫了。WPF HTML Supported TextBlock分享了一個支援有限HTML標籤的WPF控制元件。該控制元件可以支援<b>
,<u>
,<i>
,<a>
,<br>
,<font>
標籤,派生自TextBlock
控制元件,並新增了一個依賴屬性HtmlProperty
接收需要展現的html內容,使用時需要把html內容字串中的<>
用[]
代替。
Content="[font color=red]紅色[/font]文字高亮";
<toolkit:HtmlTextBlock Margin="0,0,0,0" FontSize="18"
HorizontalAlignment="Center" VerticalAlignment="Center"
Html="{Binding Content}" />
需要注意的是,用Html
繫結的內容中如果包含成對的英文方括號[]
都會被當做標籤處理,無論是否是上述支援的六種標籤,都不會顯示出來。中文方括號【】
或者單個的英文方括號則會作為內容直接顯示出來。如果用Text
繫結內容則全部當成內容顯示出來。
修改訊息對話方塊
動手寫一個簡單的訊息對話方塊中內容區域是使用可選中文字的控制元件SelectableTextBlock
顯示內容,只需全部替換為HtmlTextBlock
,並用依賴屬性HtmlProperty
繫結內容即可。呼叫的時候只需把內容改為帶標籤的內容即可。例如:
ShowAlertDialog(AlertDialogMode.Normal, AlertDialogType.Info, "開啟[a href=https://www.chinadaily.com.cn/]中國日報[/a]網站", yesbuttonText: "確定", nobuttonText: "取消", parent: this);
但在使用<a>
標籤實現連結跳轉時並沒有用瀏覽器開啟指定頁面,除錯過程中發現以下關鍵程式碼,可以看到HtmlTextBlock
是把<a>
轉換為Hyperlink
控制元件,並把href
中的url賦值給NavigateUri達到跳轉效果。
private Inline UpdateElement(HtmlTag aTag)
{
Inline retVal = null;
switch (aTag.Name)
{
case "text" :
retVal = new Run(aTag["value"]);
if (currentState.Bold) retVal = new Bold(retVal);
if (currentState.Italic) retVal = new Italic(retVal);
if (currentState.Underline) retVal = new Underline(retVal);
break;
case "br" :
retVal = new LineBreak();
break;
}
if (currentState.HyperLink != null && currentState.HyperLink != "")
{
Hyperlink link = new Hyperlink(retVal);
link.NavigateUri = new Uri(currentState.HyperLink);
retVal = link;
}
return retVal;
}
然而,只有 Hyperlink
的直接或間接父級為導航宿主時,Hyperlink
才能導航到NavigateUri
屬性的值,導航宿主包括System.Windows.Navigation.NavigationWindow
、System.Windows.Controls.Frame
或任何可承載 XBAP 的瀏覽器(包括 Internet Explorer 7、Microsoft Internet Explorer 6 和 Firefox2.0 以上版本)。因此,需要對這段程式碼稍作修改。
if (currentState.HyperLink != null && currentState.HyperLink.Length > 0)
{
Hyperlink link = new Hyperlink(retVal);
try
{
link.Click += new RoutedEventHandler((s, e) =>
{
Process.Start(new ProcessStartInfo((s as Hyperlink).NavigateUri.AbsoluteUri));
e.Handled = true;
});
}
catch(Exception ex)
{
.....
}
retVal = link;
}