マルチヘッダDataGridメモ-参(コントロールテンプレート)

まずはマルチヘッダ用のコントロールが必要となる。
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Markup;
using System.Windows.Threading;

namespace TawamureDays {

/// <summary>
/// DataGrid マルチカラムヘッダ用コントロール
/// </summary>
[ContentProperty("Content")]
public class DataGridMultiHeader : ContentControl {

#region コンストラクタ

/// <summary>
/// staticコンストラクタ
/// </summary>
static DataGridMultiHeader() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(DataGridMultiHeader),
new FrameworkPropertyMetadata(typeof(DataGridMultiHeader)));
}

#endregion
}
}

ContentPropertyは、ContentControlのお約束な属性クラス。
マルチヘッダDataGridメモ-弐(DataGridの構造を理解する)で挙げたプロパティと連携する為の依存関係プロパティを実装する。
        /// <summary>
/// セル用パネルの水平方向オフセット値を取得|設定します。
/// </summary>
private double CellsPanelHorizontalOffset {
get { return (double)GetValue(CellsPanelHorizontalOffsetProperty); }
set { SetValue(CellsPanelHorizontalOffsetProperty, value); }
}

/// <summary>セル用パネルの水平方向オフセット値</summary>
private static readonly DependencyProperty CellsPanelHorizontalOffsetProperty =
DependencyProperty.Register("CellsPanelHorizontalOffset", typeof(double),
typeof(DataGridMultiHeader), new UIPropertyMetadata(0D));

/// <summary>
/// 非固定列ViewPort(表示スペース)の水平方向オフセット値を取得|設定します。
/// </summary>
private double NonFrozenColumnsViewportHorizontalOffset {
get { return (double)GetValue(NonFrozenColumnsViewportHorizontalOffsetProperty); }
set { SetValue(NonFrozenColumnsViewportHorizontalOffsetProperty, value); }
}

/// <summary>非固定列ViewPort(表示スペース)の水平方向オフセット値</summary>
private static readonly DependencyProperty NonFrozenColumnsViewportHorizontalOffsetProperty =
DependencyProperty.Register("NonFrozenColumnsViewportHorizontalOffset", typeof(double),
typeof(DataGridMultiHeader), new UIPropertyMetadata(0D));

/// <summary>
/// 垂直方向のスクロールバーの可視状態を取得|設定します。
/// </summary>
private Visibility VerticalScrollBarVisibility {
get { return (Visibility)GetValue(VerticalScrollBarVisibilityProperty); }
set { SetValue(VerticalScrollBarVisibilityProperty, value); }
}

/// <summary>垂直方向のスクロールバーの可視状態</summary>
private static readonly DependencyProperty VerticalScrollBarVisibilityProperty =
DependencyProperty.Register("VerticalScrollBarVisibility", typeof(Visibility),
typeof(DataGridMultiHeader), new UIPropertyMetadata(Visibility.Visible));

/// <summary>
/// 垂直方向のスクロールバーの幅を取得|設定します。
/// </summary>
private double VerticalScrollBarWidth {
get { return (double)GetValue(VerticalScrollBarWidthProperty); }
set { SetValue(VerticalScrollBarWidthProperty, value); }
}

/// <summary>垂直方向のスクロールバーの幅</summary>
private static readonly DependencyProperty VerticalScrollBarWidthProperty =
DependencyProperty.Register("VerticalScrollBarWidth", typeof(double),
typeof(DataGridMultiHeader), new UIPropertyMetadata(0D));

次、テンプレートを作るにあたって、基本的な構造を考える。
DataGridが持つ列ヘッダは、専用のItemsControlに格納されている。更にこのItemsControlには、専用のパネルクラスが利用されている。しかも、DataGridというコントロールの内部で利用される事が前提となっている、いわゆるワンオフなクラス群だったりする。最初、これ(DataGrid内で使われているロジック)を再利用できないかと、ソースコードとにらめっこした。大体は理解できるんだけど、マルチヘッダに利用できるか?と考えたら、「無理っぽい」という結論になってしまった。なので、WPF multi-column super headerにあったように、Gridパネルを駆使してどうにかする方法を考えた次第。

コントロールテンプレート実装メモ:
①DataGridを覆う為のDockPanelを準備する。
②DataGridの上部に張り付く為のBorder(DockPanel.Dock=Top)を①のDockPanelに追加する。
③DataGridはContentに設定される前提なので、ContentPresenterを①のDockPanelに追加する。
なので最も外側だけで見ると、DockPanel{Border(Top), ContentPresenter}になる。
④Border内に、各々の領域を確保する為のGridを追加する。
⑤④で追加したGridに、以下のコントロールを追加する。
 Rectangle:CellsPanelHorizontalOffset分の広さを確保する為のプレースホルダ
      DataGridRowHeaderの上あたりに居座る。
 Grid:固定列分の領域を確保するためのプレースホルダ。固定列用のマルチヘッダを表示させる領域になる。
 ScrollViewer:可変列分の領域を確保する為のプレースホルダ。DataGridがスクロールされのと同じようにスクロールされる必要がある。
 Rectangle:垂直方向のスクロールバー分の領域を確保する為のプレースホルダ。スクロールバーがAutoだった時も考える。
※各プレースホルダの幅や表示状態は、領域確保の対象とする部分と連携される。
マルチヘッダの部分は、GridとScrollViewer内に収められる。
(追記)
③くらいまでの段階におけるControlTemplate。
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TawamureDays">
<Style TargetType="{x:Type local:DataGridMultiHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DataGridMultiHeader}">
<DockPanel>
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True"
DockPanel.Dock="Top">
</Border>
<ContentPresenter/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Styleの宣言、TargetTypeの設定、TemplateプロパティへのSetはお約束。カスタムコントロールのControlTemplateもワンオフ品かな。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


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

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

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

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