見た目だけそれっぽい。

後輩が、とある画面で、DataGridの列にハイパーリンクを表示しようとしたらしい。

後輩:ちょっと良いっすか?
自分:ん?なに?
後輩:DataGridHyperlinkColumnを使おうとしてるんっすけど、どうにも動かないんすよ。
自分:どれどれ?
後輩:ほら。押しても反応ないっす。
自分:ほんとだ。

(注)実際は、こんなにチャラい訳ではありません。
見た目は、きっちりとハイパーリンクな感じに見えるんだけど、それだけ。まさに押した時のカスカス感がなんだか物悲しい。で、どうなってるんだと、この標準装備であるところのDataGridHyperlinkColumnを調べる事になった。
DataGridHyperlinkColumn クラス
この中のメモ欄にこう書かれてあった。

Hyperlink による移動が行われるのは、Hyperlink の直接または間接的な親がナビゲーション ホストである場合だけです。 ナビゲーション ホストの例には、NavigationWindow、Frame、または Microsoft Internet Explorer 6 以降および Firefox 2.0 以降など、XBAP をホストできるブラウザーが含まれます。

ナビゲーションホスト?
ナビゲーションホスト
引用:

ナビゲーション ホストは、コンテンツにナビゲートして表示することができるクラスです。

日本語って、横文字率が増えると訳わからなくなるな…。まあ、ブラウザの様に、「進む」や「戻る」でページ遷移し、さらに履歴を保持できるようなクラス上でなければ、動かないという事らしい。うーん。でもそれって、普通のWindow上では見た目だけって事になってしまう。TemplateColumnで作るって手もあるけど、一々同じテンプレートを設定するか、そのテンプレートを持ち運ぶ事になってしまう。
で、仕事では、DataGridHyperlinkColumnを拡張することにした。
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace TawamureDays {

/// <summary>
/// 拡張ハイパーリンク用DataGridColumnクラス
/// </summary>
/// <remarks>
/// DataGridHyperlinkColumnを拡張したクラス<br/>
/// <br/>
/// </remarks>
public class ExtendedHyperlinkColumn : DataGridHyperlinkColumn {

#region FrameworkElement Member

/// <summary>
/// 列の Binding プロパティ値にバインドされた読み取り専用の TextBlock コントロールを取得します。
/// </summary>
/// <remarks>
/// 値が入る前なので、ここで値の編集とかはできない。
/// </remarks>
/// <param name="cell">生成された要素を格納するセル。</param>
/// <param name="dataItem">目的のセルを格納している行によって表されるデータ項目。</param>
/// <returns>列の Binding プロパティ値にバインドされた新しい読み取り専用のテキスト ブロック コントロール</returns>
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
var txtBlock = (TextBlock)base.GenerateElement(cell, dataItem);

txtBlock.Unloaded += new RoutedEventHandler(TextBlock_Unloaded);
txtBlock.AddHandler(Hyperlink.ClickEvent, new RoutedEventHandler(OnHyperlinkClick));

return txtBlock;
}

#endregion

#region Event Method

/// <summary>
/// Hyperlinkクリックイベント用メソッド
/// </summary>
/// <param name="sender">イベントソース/param>
/// <param name="e">イベントデータ</param>
private void OnHyperlinkClick(object sender, RoutedEventArgs e) {

var hyperlink = (e.OriginalSource as Hyperlink) ?? (e.Source as Hyperlink);

if (hyperlink != null && !string.IsNullOrWhiteSpace(hyperlink.NavigateUri.AbsoluteUri)) {
//かんれんづいているブラウザで開かれます。
System.Diagnostics.Process.Start(hyperlink.NavigateUri.AbsoluteUri);
}

return;
}

/// <summary>
/// TextBlockアンロードイベント用メソッド
/// </summary>
/// <param name="sender">イベントソース/param>
/// <param name="e">イベントデータ</param>
private void TextBlock_Unloaded(object sender, RoutedEventArgs e) {
var txtBlock = sender as TextBlock;
txtBlock.Unloaded -= new RoutedEventHandler(TextBlock_Unloaded);
txtBlock.RemoveHandler(Hyperlink.ClickEvent, new RoutedEventHandler(OnHyperlinkClick));

return;
}

#endregion
}
}
 Hyperlink.ClickEventにハンドラ用メソッドを登録し、URLからブラウザを起動するように実装した。こうしておけば、ナビゲーションホスト以外でも使うことが可能になる。Unloadedイベントは、メモリリーク予防の為に、ハンドラの削除を行っている。Unloadedイベントは、スクロールによる非表示(表示領域から外れる事)や表示モードから編集モードへ移った時にも発生する。ハンドラから削除できる時にしておかないと、一度のイベントハンドラが何重にも呼び出される可能性もあるので、その辺りを面倒臭がるわけにもいかなのだ。
 これを使えば、どうにかなるかな。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m