かずきのBlog

C#やJavaやRubyとメモ書き

目次

Blog 利用状況

ニュース

わんくまBlogが不安定になったため、前に書いてたはてなダイアリーにメインを移動します。
かずきのBlog@Hatena
技術的なネタは、こちらにも、はてなへのリンクという形で掲載しますが、雑多ネタははてなダイアリーだけに掲載することが多いと思います。
コメント
プログラマ的自己紹介
お気に入りのツール/IDE
プロフィール
経歴
広告
アクセサリ

書庫

日記カテゴリ

[WPF][C#]ListViewのGridViewに罫線を引きたい

個人的に、ListViewのGridViewにほしいなと思う機能として

  1. セルに罫線を引きたい
  2. 横スクロール時に常に表示される列を指定したい
  3. 出来るなら、Excelみたいな編集ができると嬉しい

あたりを常々思っています。
どれも、WPFToolkitのDataGridを使えば不満は解決されるのですが、なんというか正式リリース前のものということで、遊ぶのには最適だけど実際に使うにはどうかなぁ・・・と思ってたりしています。
簡単に触った範囲内では、バグらしきものも見当たらないので多分大丈夫だと思ってはいます。

今回は、このListViewのGridViewにほしい機能の1つである「セルに罫線を引きたい」といった部分をゴリっと力技?でやってみようと思います。

下準備

とりあえず、下準備として普通にListViewのGridViewにデータを表示するものを作ってみようと思います。そこに罫線表示を付け加えていくという流れです。

WpfListViewGridLineという名前でプロジェクトを新規作成します。

プロジェクトを作成したら、表示するデータを格納するクラスとして、いつものPersonクラスを作成します。

namespace WpfListViewGridLine
{
    public class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

Personクラスを作成したら、Window1クラスのコンストラクタでダミーのデータ2000件くらいをDataContextに入れておきます。

using System.Linq;
using System.Windows;

namespace WpfListViewGridLine
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            // ダミーデータ作成
            DataContext = Enumerable.Range(1, 2000).Select(i =>
                new Person
                {
                    ID = i,
                    Name = "田中 太郎 " + i,
                    Age = i % 100
                });
        }
    }
}

ダミーデータを作成したら、それを表示するListViewをWindow1.xamlのほうに書いていきます。
ここでは、単純にGridViewColumnを使って表示するだけです。

<Window x:Class="WpfListViewGridLine.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <ListView ItemsSource="{Binding}" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
                    <GridViewColumn Header="名前" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="年齢" DisplayMemberBinding="{Binding Age, StringFormat={}{0}際}" />
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

ここまでで実行すると、以下のようにListViewにデータが表示されます。
image

罫線表示を作りこんでいく

下準備が出来たので、罫線を表示する部分を作りこんでいきます。
罫線は、ListViewの一行を表すクラスであるListViewItemに対するスタイルで色々やることで実現します。
そのため、WindowのResourcesにStyleを1つ定義して、そいつをListViewのItemContainerStyleに設定します。

<Window x:Class="WpfListViewGridLine.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <Style x:Key="lineGridStyle" TargetType="{x:Type ListViewItem}">
            <!-- TODO: ここに罫線に関するスタイルを定義する -->
        </Style>
    </Window.Resources>
    <Grid>
        <ListView ItemsSource="{Binding}" 
                  ItemContainerStyle="{StaticResource lineGridStyle}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" />
                    <GridViewColumn Header="名前" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="年齢" DisplayMemberBinding="{Binding Age, StringFormat={}{0}際}" />
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

※)ここから先に示すXAMLは、Window.Resourcesの下のlineGridStyleのみになります。

罫線を引くためのメカニズムですが、ListViewItemクラスには、そういったプロパティがないので力技を使うことになります。
具体的に言うと、ListViewItemのTemplateを差し替えて罫線を表示するものにしてしまう!ということになります。

とりあえず、GridViewRowPresenterを置いて、もとの見た目を復元します。

<Style x:Key="lineGridStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <!-- まず、元の見た目を再現 -->
                <GridViewRowPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

実行して、見た目が以前と変わらないことを確認します。
image 

この状態だと、選択行の色が変わらないので、色がつくようにします。
ListViewのGridViewを使ったときみたいな綺麗なグラデーションがかった色にしたかったのですが、やりかたがわからなかったのでListBoxと同じ色になるようにしました。
ここらへんの上手いやり方がわかる型はコメントくださいm(_ _)m

選択時に色買えは、背景色と前景色を指定するためのGridとContentControlをTemplateに新たに置いて、TriggersプロパティにIsSelectedがTrueの時にシステムカラーからそれっぽい色を設定するようにしました。

<Style x:Key="lineGridStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <!-- 背景色担当 -->
                <Grid Name="background">
                    <!-- 前景色担当 -->
                    <ContentControl Name="foreground">
                        <GridViewRowPresenter />
                    </ContentControl>
                </Grid>
                <ControlTemplate.Triggers>
                    <!-- 選択されている場合 -->
                    <Trigger Property="IsSelected" Value="True">
                        <!-- 背景色をハイライト時の拝啓色に -->
                        <Setter TargetName="background"
                                Property="Background"
                                Value="{x:Static SystemColors.HighlightBrush}" />
                        <!-- 前景色をハイライト時のテキストの色に -->
                        <Setter TargetName="foreground" 
                                Property="Foreground"
                                Value="{x:Static SystemColors.HighlightTextBrush}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

これで選択時にそれっぽい色になります。
image

ここまで長かったですが、ついに罫線表示の部分を作りこんでいきます。
罫線は、GridViewRowPresenterの上に、罫線のレイヤを重ねることで表示させます。表示するために必要な矩形は、GridViewRowPresenterのColumnsプロパティとバインドしたItemsControlにBorderを表示させることで実現しています。

<Style x:Key="lineGridStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Grid Name="background">
                    <ContentControl Name="foreground">
                        <!-- バインドするために名前をつけた -->
                        <GridViewRowPresenter Name="rowPresenter"/>
                    </ContentControl>
                    <!-- GridViewRowPresenterのColumnsとバインド! -->
                    <ItemsControl ItemsSource="{Binding ElementName=rowPresenter, Path=Columns}">
                        <!-- 表示は水平方向に -->
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal" />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        
                        <!-- ボーダーを表示する -->
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <!-- 右側と下側に罫線を引く、ボーダーの幅は列の表示幅にバインドする -->
                                <Border Margin="1,0,0,0"
                                        BorderBrush="Gray"
                                        BorderThickness="0,0,1,1" 
                                        Width="{Binding ActualWidth}"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="background"
                                Property="Background"
                                Value="{x:Static SystemColors.HighlightBrush}" />
                        <Setter TargetName="foreground" 
                                Property="Foreground"
                                Value="{x:Static SystemColors.HighlightTextBrush}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ここまでで実行すると、見た目上できてそうに見えるところまで完成です。
image

実は、この状態だと、セル内の余白部分をクリックしても行選択が出来ないという悲しいことがおきます。
なので、行いっぱいに表示するようにして、この問題を解決して完成です。

<Style x:Key="lineGridStyle" TargetType="{x:Type ListViewItem}">
    <!-- セル内の余白部分をクックしても行選択になるようにする -->
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Grid Name="background">
                    <ContentControl Name="foreground">
                        <GridViewRowPresenter Name="rowPresenter"/>
                    </ContentControl>
                    <ItemsControl ItemsSource="{Binding ElementName=rowPresenter, Path=Columns}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel Orientation="Horizontal" />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Border Margin="1,0,0,0"
                                        BorderBrush="Gray"
                                        BorderThickness="0,0,1,1" 
                                        Width="{Binding ActualWidth}"/>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="background"
                                Property="Background"
                                Value="{x:Static SystemColors.HighlightBrush}" />
                        <Setter TargetName="foreground" 
                                Property="Foreground"
                                Value="{x:Static SystemColors.HighlightTextBrush}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

実行して動きを確認すると…
image 
いい感じ。

投稿日時 : 2009年5月6日 19:36

Feedback

# re: [WPF][C#]ListViewのGridViewに罫線を引きたい 2009/05/06 21:32 aetos

際ちがうよー。

# re: [WPF][C#]ListViewのGridViewに罫線を引きたい 2009/05/06 23:57 かずき

本当だ~!?
一貫して間違えてるのでとりあえずこのままで・・・orz

# [WPF][C#]ListViewのGridViewに罫線を引きたい その2 2009/05/12 0:46 かずきのBlog

[WPF][C#]ListViewのGridViewに罫線を引きたい その2

# longchamp bags black 2012/12/14 20:40 http://www.longchampbagoutlet.info/category/longch

I am impressed by products you can information about this website. There are a whole lot of good means here.

# handbags burberry 2012/12/15 22:49 http://www.burberryuksale.info/category/burberry-u

Go with these elder items and look for your that tickle your current fancy.

# longchamp pliage hobo 2012/12/16 17:51 http://www.soldesacslongchamp.info/category/sacs-l

The stars in this pool is the comments as well as pictures tend to be secondary.

# burberry online 2012/12/17 2:42 http://www.burberryuksale.org/category/burberry-on

You extremely know a person's stuff...

# エルメス時計 2012/12/17 20:55 http://www.hermespairs.info

I really like em. It's not wish you slip on these out walking on town folks.

# bottes isabel marant 2012/12/18 2:01 http://isabelmarantbottes.webnode.fr

The stars about this pool will be the comments and therefore the pictures can be secondary.

# Burberry sortie 2012/12/19 13:41 http://sacburberrysoldesfr.webnode.fr/actualites

Think it for a journal or perhaps a magazine of general interest proper to learn. Funny, witty, controversial, entertaining, useful, acerbic, thoughtful, serious, curious, unexpected comebacks usually are welcome.

# http://www.destockchinefr.fr/maillot-de-club-pas-cher/serie-a-pas-cher/ 2013/01/13 4:31 http://www.destockchinefr.fr/maillot-de-club-pas-c

Irrrm a sucker for you do not like a what you are, although like a what individuals Now i am as i have always been along with you.
http://www.destockchinefr.fr/maillot-de-club-pas-cher/serie-a-pas-cher/ http://www.destockchinefr.fr/maillot-de-club-pas-cher/serie-a-pas-cher/

# DuqkjevvwJWoOfBrgdC 2014/08/28 4:56 http://crorkz.com/

Gy5TqM Well I really enjoyed reading it. This article procured by you is very useful for accurate planning.

# LktkWSyvnBQcBgx 2015/04/30 6:38 chaba

Pn1awQ http://www.FyLitCl7Pf7kjQdDUOLQOuaxTXbj5iNG.com

# re: [WPF][C#]ListViewのGridViewに罫線を引きたい 2016/03/03 9:48 grid4

たいへん勉強になりました。
ありがとうございました!!

# 激安ブランドのオーデマピゲ腕時計 2020/07/18 15:50 mrlamyf@excite.co.jp

ぜひ購入の際の参考にしてくださいね! エコスタイル新宿三丁目店ではベル&ロスを買取強化しております。
時計専門店GMTおよび下記サイトは、「シュッピン株式会社」が運営しております。
そこで今回は、フォッシルの腕時計の選び方のポイントと、人気のモデルをレディースとメンズに分けて、それぞれランキング形式でご紹介。
そこで今回は、40万円台の腕時計を、メンズ・レディースの人気ランキング形式でご紹介! どれも、いつかは手に入れたい上質でおすすめの腕時計ばかり。
ベルトの素材や文字盤のタイプ、防水性能などそれぞれ違いがありますが、どこに注目して選べばお気に入りが見つかるのでしょうか?
予算が100万円以上になると、ロレックス・オメガと言った世界的ブランドのモデルも選択肢に入りますが、年収に見合ってる?
おすすめのアイテムが多数登場しますので、ぜひ理想的な腕時計選びの参考にご一読くださいね。
数日おきにするのが面倒なセルフ処理を、楽にしてくれるのが除毛クリームです。
季節問わず、女性に必須のムダ毛処理。
男性からも女性からも好感度の高い白文字盤。
個性的なスタイルのミリタリーウォッチとして、航空機の計器に通じる大型で視認性の高いデザインが特徴です。
クロノグラフ搭載モデルの「ヴィンテージ BR 126 エアロナバル」もありますが、個人的に今回購入した3針モデルの方が好みでした。
おしゃれなデザインのモデルもたくさんありますが、いざ購入しようと思うとどれを選べばよいか悩んでしまいますよね。
そんなプロトレックですが、実に多くのラインナップが存在しており、いざ購入しようとなると、かなり悩ましいものです。
価格が安いだけでなくデザインがおしゃれなこと、また品質が高いことからも注目を集めている腕時計です。
小さなケースの中で時を刻み続ける、腕時計。
スイスの高級時計ブランドの一つ、ウブロ。

激安ブランドのオーデマピゲ腕時計 https://www.cocoejp.com/ProductList.aspx?TypeId=345925719326463

タイトル  
名前  
Url
コメント