情報アイランド

「情報を制する者は世界を制す」をモットーに様々な情報を提供することを目指すブログです。現在はプログラミング関連情報が多めですが、投資関連情報も取り扱っていきたいです。

WPFでオブジェクト木の探索

よく使うので拡張メソッドにしてみました。

public static T GetVisualObject<T>(this DependencyObject dependencyObject) where T : class
{
    if (dependencyObject is T || dependencyObject == null)
        return dependencyObject as T;

    return GetVisualObject<T>(VisualTreeHelper.GetParent(dependencyObject));
}

public static T GetLogicalObject<T>(this DependencyObject dependencyObject) where T : class
{
    if (dependencyObject is T || dependencyObject == null)
        return dependencyObject as T;

   return GetLogicalObject<T>(LogicalTreeHelper.GetParent(dependencyObject));
}

使用例。

DataGridのコンテキストメニューの表示に使ってみます。

DataGrid.ContextMenuプロパティの内部に直接MenuItemを追加すると、DataGridの全ての領域で同じメニューが表示されてしまいます。

列頭の部分と項目の部分で別のメニューを表示させたいことが多いと思います。

ColumnHeaderStyleRowStyleを使うという方法もありますが(JZ5氏が取り上げています:WPF Toolkit DataGrid ContextMenu とクリック処理)、ここではマウスポインタの下にあるオブジェクトから表示すべきメニューを判定するという方法を紹介します。

まずは、XAML。予めDataGridに空のコンテキストメニューを配置しておきます。

ContextMenuOpeningイベントを処理します。

<dg:DataGrid x:Name="dgSearch" AutoGenerateColumns="False" GridLinesVisibility="None" SelectionUnit="FullRow" IsReadOnly="True" ContextMenuOpening="dgSearch_ContextMenuOpening">
    <dg:DataGrid.ContextMenu>
        <ContextMenu x:Name="cmSearch"></ContextMenu>
    </dg:DataGrid.ContextMenu>
    <dg:DataGrid.Columns>
        (省略)
    </dg:DataGrid.Columns>
</dg:DataGrid>

ContextMenuOpeningイベントハンドラ。

赤字の部分でGetVisualObject<T>を使用しています。DataGridColumnHeaderが見付かったら列頭で、DataGridRowが見付かったら項目部分です。

最後に、それ以外の場所で空のメニューが表示されないように、e.Handledtrueに設定します。

private void dgSearch_ContextMenuOpening(object sender, ContextMenuEventArgs e)
{
    DataGridColumnHeader dataGridColumnHeader = (Mouse.DirectlyOver as DependencyObject).GetVisualObject<DataGridColumnHeader>();
    if (dataGridColumnHeader != null)
    {
        cmSearch.Items.Clear();

        MenuItem menuItemHide = new MenuItem() { Header = "隠す(_H)" };
        menuItemHide.Click += (sender2, e2) =>
        {
            dataGridColumnHeader.Column.Visibility = Visibility.Collapsed;
        };

        MenuItem menuItemColumnConfigure = new MenuItem() { Header = "列の構成(_C)..." };
        menuItemColumnConfigure.Click += (sender2, e2) =>
        {
            new SearchColumnConfigureWindow() { Owner = App.Current.MainWindow }.ShowDialog();
        };

        cmSearch.Items.Add(menuItemHide);
        cmSearch.Items.Add(new Separator());
        cmSearch.Items.Add(menuItemColumnConfigure);

        return;
    }

    DataGridRow dataGridRow = (Mouse.DirectlyOver as DependencyObject).GetVisualObject<DataGridRow>();
    if (dataGridRow != null)
    {
        (省略)

        return;
    }

    e.Handled = true;
}
pizyumi
プログラミング歴19年のベテランプログラマー。業務システム全般何でも作れます。現在はWeb系の技術を勉強中。
スポンサーリンク

-C#, wpf