DataGridCellにツールチップ(Tooltip)を(弐)

DataGridCellにツールチップ(Tooltip)を(壱)の続き
DataGridCellにToolTipを表示させるため、Converterクラスを作ることにしたがが、その前に、課題にある「DataGridCellから表示内容を取得する」為に、関係するプロパティ名を取得する拡張メソッドを実装した。
/// <summary>
/// 指定のDataGridColumnに関係するパス(プロパティ名)を取得します。
/// </summary>
/// <param name="column">DataGridColumn</param>
/// <returns>DataGridColumnに関係するパス(プロパティ名)</returns>
public static string ResolveMemberPath(this DataGridColumn column) {

//DataGridTemplateColumnは、DataGridBoundColumn系ではないので、
//SortMemberPathを返します。
var path = column.SortMemberPath;

if (!string.IsNullOrEmpty(path)) {
return path;
}

//DataGridComboBoxColumn列なら、アイテムを表すDisplayMemberPathを返します。
if (column is DataGridComboBoxColumn) {
return ((DataGridComboBoxColumn)column).DisplayMemberPath;
}

//DataGridBoundColumn 系の列で、Data Bindingされているなら、
//そのBinding情報からPathを取得して返します。
var binding = (column as DataGridBoundColumn)?.Binding as Binding;

if (!string.IsNullOrEmpty(binding?.XPath)) {
return binding.XPath;

} else if (binding?.Path != null) {
return binding.Path.Path;
}

return path;
}
ん。null演算子を使うと、それなりにすっきりする。仕事ではまだつかえないけど( ノД`)。拡張メソッドにしてあるので、staticクラスに実装している。これを使って、Converterクラスを実装する。なお、このメソッドは、今回以外にも使える有能さんだったことが後で判明した。
このメソッドを使って、Converterクラスを実装する。
using System.ComponentModel;
using System.Windows.Controls;
using System.Windows.Data;

namespace TawamureDays {

/// <summary>
/// DataGridCellから、それに表示されている文字列へ変換するコンバーター
/// </summary>
[ValueConversion(typeof(System.Windows.Controls.DataGridCell), typeof(string))]
public class Cell2StringConverter : System.Windows.Data.IValueConverter {

#region IValueConverter Member

/// <summary>
/// 値を変換します。
/// </summary>
/// <param name="value">バインディング ソースによって生成された値。</param>
/// <param name="targetType">バインディング ターゲット プロパティの型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {

if ((value as DataGridCell)?.DataContext == null) {
return string.Empty;
}

var cell = value as DataGridCell;
var path = cell.Column?.ResolveMemberPath();

if (string.IsNullOrEmpty(path)) {
return string.Empty;
}

var properties = TypeDescriptor.GetProperties(cell.DataContext);

if (properties != null && properties.Count > 0) {
return properties.Find(path)?.GetValue(cell.DataContext)?.ToString() ?? string.Empty;
}

return string.Empty;
}

/// <summary>
/// 値を変換します。(未サポート)
/// </summary>
/// <param name="value">バインディング ターゲットによって生成される値。</param>
/// <param name="targetType">変換後の型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotSupportedException("Cannot convert(string -> DataGridCell).");
}

#endregion
}
}

〇DataGridCellに表示内容から表示状態(Visibility)へ変換するConverter
[ValueConversion(typeof(System.Windows.Controls.DataGridCell), typeof(Visibility))]
public class Cell2VisibilityConverter : System.Windows.Data.IValueConverter {

/// <summary>
/// 値を変換します。
/// </summary>
/// <param name="value">バインディング ソースによって生成された値。</param>
/// <param name="targetType">バインディング ターゲット プロパティの型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {

if ((value as DataGridCell)?.DataContext == null) {
return Visibility.Collapsed;
}

var cell = value as DataGridCell;
var path = cell.Column?.ResolveMemberPath();

if (string.IsNullOrEmpty(path)) {
return Visibility.Collapsed;
}

var properties = TypeDescriptor.GetProperties(cell.DataContext);

if (properties != null && properties.Count > 0) {
return string.IsNullOrEmpty(
properties.Find(path)?.GetValue(cell.DataContext)?.ToString()) ?
Visibility.Collapsed : Visibility.Visible;
}

return Visibility.Collapsed;
}
}
usingとConverBackは割愛する。
〇XAML Styleを作成する。
<Windows.Resources>
<conv:Cell2StringConverter x:Key="Cell2StringConverter"/>
<conv:Cell2VisibilityConverter x:Key="Cell2VisibilityConverter"/>
<Style x:Key="ToolTipCellStyle" TargetType="{x:Type DataGridCell}"
BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding Path=PlacementTarget,Mode=OneWay,
               RelativeSource={x:Static RelativeSource.Self}}"
Visibility="{Binding Mode=OneWay,
Converter={StaticResource Cell2VisibilityConverter}}">
<StackPanel>
<TextBlock Text="{Binding Mode=OneWay,
Converter={StaticResource Cell2StringConverter}}"/>
</StackPanel>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
</Windows.Resources>

後は、これをDataGridのCellStyleに設定するだけである。
DataGridCellにToolTip
ただし、この実装にも若干の問題は残っている。
〇配列やリスト型の列に設定すると、内容ではなく、クラスタイプがToolTipに表示される。
  -Converter内でvalueのクラスタイプをチェックするしかない。
〇SortMemberPath頼み。
  -これはもう、プロジェクトで方針を決めるしかない。
〇プロパティ名から値を取得する部分は、パフォーマンス的にはよろしくない。
  -これは工夫するしかない。仕事では式木を使って若干速度を上げた。

作成して以来、これを仕事で使い続けているが、問題は発生していないかな。一応、必要そうな列だけに設定するように心がけてはいるけど。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


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

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

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

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