mogmo .NET

C#/XAML/VB6たまにC++についてメモ程度に書いていく。あくまで自分用。責任は取れません。

C#からDataGrid内のコントロールにアクセスする

DataGridでColumnsにDataGridTrmplateColumnを置き,表示する内容を色々とカスタマイズすることが多い。
ここでたまに困るのが,DataGridTemplateColumnの中のDataTemplate内のコントロールにアクセスするとき。

何度かつまづいたので,メモする。

ポイント

MacのFinderや,Visual Studioのソリューションエクスプローラのようなツリー風のDataGridを作成した。
その時のコードを元に,ポイントを書いていく。

DataGridTemplateColumn

以下のように書いた。今回は,TreeToggleButtonにアクセスしたい。

<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <ToggleButton x:Name="TreeToggleButton" Style="{StaticResource TreeToggleButtonStyle}"/>
                <Image Source="{Binding Converter={StaticResource NodeTypeIconConverter}}"  Margin="0, 0, 5, 0"/>
                <TextBlock Text="{Binding Path=Title}"/>
            </StackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

コントロールを見つける処理を作る

// 子を検索する。見つからなければ孫を検索する。
private T FindVisualChild<T>(DependencyObject reference) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(reference, i);
        if (child != null && child is T)
        {
            return (T)child;
        }
        else
        {
            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild != null)
                return childOfChild;
        }
    }
    return null;
}

実際にどう扱うか

ToggleButtonを見つける処理を以下のようにかいた。
TreeDataGridRowクラス(DataGridRowを継承した自作クラス)で行を渡し,rowのContentPresenterからDataGridCellを取得する。cellの子要素でToggleButtonであるものを更に検索する。

private bool HittingTreeToggleButton(TreeDataGridRow row, GetDragDropPosition position)
{
    if (row == null)
        return false;

    var contentPresenter = FindVisualChild<ContentPresenter>(row);
    if (!(contentPresenter.TemplatedParent is DataGridCell cell))
        return false;

    if (!(cell.Column is DataGridTemplateColumn templateColumn))
        return false;

    ToggleButton toggleButton = FindVisualChild<ToggleButton>(cell);
    if (toggleButton.Name != "TreeToggleButton")
        return false;

    if (IsMouseOnTargetRow(toggleButton, position))
        return true;
    else
        return false;
}

問題

cellのなかにToggleButtonが2つある場合は1つしか取得できないという問題がある。

        • mogmo