2009年1月26日月曜日

ListViewを縞々にして罫線を描いて選択行の背景色を任意に設定する

ListViewを縞々にするのは色々やり方があるけれど、汎用性という意味では、ItemContainerStyleSelectorを使う方法が一番良い。罫線を引く時に、BorderThicknessを最初は1, 1, 1, 1にして残りは全て1, 0, 1, 1にするなんて事はAlternationCountなんかを使っては実現できない。

しかし、ListViewの.ItemContainerStyleSelectorを設定すると、ItemContainerStyleの設定が無視される(カスケーディングされない)し、ListViewItemをターゲットにしたデフォルトスタイルを設定していも何故かそれも無視されてシステムのデフォルトのスタイルになってしまう。このため、このエントリのタイトルに書いた事を全部実現するのは結構大変。

結局ListViewのリソースにクラシックスタイルからキー名GridViewItemContainerStyleKeyのテンプレートを丸ごとコピーしてトリガーを削除したテンプレートを書いておいて、ItemContainerStyleSelectorではそれをTemplateプロパティに割り当てた上でIsSelectedプロパティに対するトリガーも設定し、さらに縞々や罫線の設定をするという方針で解決した。

xamlは例えばこんな感じ:

<ListView Grid.Row="3" Name="StockList" ItemsSource="{Binding}" VerticalAlignment="Stretch" SelectionMode="Single" Background="#FFEDFEED">
<ListView.Resources>
<ControlTemplate TargetType="{x:Type ListViewItem}"
x:Key="ListViewItemWithoutAnyTrigger">
<Border Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<GridViewRowPresenter
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="コード" Width="Auto"
DisplayMemberBinding="{Binding Path=Code}" />
・・・ほにゃらら・・・
</GridView>
</ListView.View>
</ListView>

で、StyleSelectorはこんな感じ:

public class StockListItemStyleSelector : StyleSelector
{
public Color Back1 = Colors.White, Fore1 = Colors.Black,
Back2 = Colors.White, Fore2 = Colors.Black,
BackSelection = Colors.Red, ForeSelection = Colors.Green,
Rule = Colors.Beige;
public override Style SelectStyle(object item, DependencyObject container)
{
ListView listView = ItemsControl.ItemsControlFromItemContainer(container) as ListView;
int index = listView.ItemContainerGenerator.IndexFromContainer(container);

Style stockListItemStyle = new Style(typeof(ListViewItem));

//トリガーを除いたテンプレートに設定
stockListItemStyle.Setters.Add(new Setter(ListViewItem.TemplateProperty,
listView.Resources["ListViewItemWithoutAnyTrigger"]));

//背景色、前景色を縞々にする
stockListItemStyle.Setters
.Add(new Setter(ListViewItem.BackgroundProperty,
new SolidColorBrush(index % 2 == 0 ? Back1 : Back2)));
stockListItemStyle.Setters
.Add(new Setter(ListViewItem.ForegroundProperty,
new SolidColorBrush(index % 2 == 0 ? Fore1 : Fore2)));

//罫線を設定する
stockListItemStyle.Setters
.Add(new Setter(ListViewItem.BorderBrushProperty,
new SolidColorBrush(Rule)));
stockListItemStyle.Setters
.Add(new Setter(ListViewItem.BorderThicknessProperty,
new Thickness(index==0?1:0, 1, 1, 1)));

//選択行の色を設定する
Trigger selectionTrigger = new Trigger() {
Property = ListViewItem.IsSelectedProperty,
Value = true
};
selectionTrigger.Setters.Add(new Setter(ListViewItem.BackgroundProperty,
new SolidColorBrush(BackSelection)));
selectionTrigger.Setters.Add(new Setter(ListViewItem.ForegroundProperty,
new SolidColorBrush(ForeSelection)));
stockListItemStyle.Triggers.Add(selectionTrigger);

return stockListItemStyle;
}
}

これでstockListPanel.StockList.ItemContainerStyleSelector = new StockListItemStyleSelector() {Back1=ほにゃらら・・・};とやれば良い。

良かった良かった。

0 件のコメント: