none
ListViewの行データの『...』表示を行うためには RRS feed

  • 質問

  • こんにちは。おひさしぶりです。

    WPFの
    ListViewで、行データの『...』表示を行うためには、通常コントロールではだめなのでしょうか?
    また、それと合わせて、『...』表示になった場合に、ToolTipも表示させたいと思っています。

    エクスプローラなどでは、ファイル名がカラム幅より小さくなると、自動的にそのカラムの行データが『...』になりますよね?
    あれはListViewでは実現できないのでしょうか?

    大変申し訳ございませんが、ご教授お願いいたします。
    koki
    2009年6月14日 23:59

回答

  • kokiさんの、やろうとしてるやり方で私も色々試してみたのですが現時点で出来ませんでしたorz
    代わりといっては何ですが、添付プロパティあたりをちょっといじくって簡単に適用できるようなものを
    作ってみました。

    私のBlogで恐縮なのですが、以下のエントリにコードとかをのせています。
    http://blogs.wankuma.com/kazuki/archive/2009/06/23/176419.aspx


    かずき Blog:http://blogs.wankuma.com/kazuki/
    • 回答としてマーク Koki Shimizu 2009年6月23日 16:06
    2009年6月23日 14:20

すべての返信

  • 以下のようにしてみて下さい。

    <GridViewColumn.CellTemplate>
        <DataTemplate>
             <TextBlock Text="{Binding hoge}" TextTrimming="WordEllipsis" />
        </DataTemplate>
    </GridViewColumn.CellTemplate>

    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/
    2009年6月15日 1:26
    モデレータ
  • 早速のご返信、ありがとうございます。
    大変申し訳ございません、少し言葉足らずでした。
    trapemiya様にご回答いただいた方法は既に試してみました。通常なら上記のようなXAMLでいけるはずです。

    ただ、今回私が行いたいことは、以下のとおりです。

    CellTemplateを使わずに、DisplayMemberBindingのみを指定して、
    ListViewにString型のDataColumnをもつDataTableをBindingしたときに、
    ListViewのセル内の全ての文字列が、表示幅に応じて『...』を表示するようにしたい。

    このような場合、おそらくBinding先が可変になってしまうので難しいかと思いますが、
    ご教授お願いいたします。

    koki
    2009年6月15日 3:56
  • CellTemplateを使わずに、DisplayMemberBindingのみを指定すると、VirtualizingStackPanel を作成し、内部で ListBoxItem を生成します。
    ListBoxItem の Content プロパティ に TextBlock を生成しているものと思われます。

    上記情報をもとにご自分で ListView の ItemsPanel に ItemsPanelTemplate を作成されたらうまくいくかもしれません。

    このページの下のサンプルの応用です。
    http://msdn.microsoft.com/ja-jp/library/system.windows.controls.itemscontrol.itemspanel.aspx

    TemplateBinding も使わないといけないかもしれません。
    http://msdn.microsoft.com/ja-jp/library/ms742882.aspx

    ご自分でできそうになかったら、trapemiya さんの方法(こちらが通常の解決方法です)を使うかどちらかです。

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年6月15日 18:05
  • この状態から ItemsPresenter のあたりを変更していくのもいいかもしれません。

    <Window
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	x:Class="GridViewCheck.Window1"
    	x:Name="Window"
    	Title="Window1"
    	Width="640" Height="480" xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero">
    
    	<Window.Resources>
    		<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
    		<Style x:Key="{x:Static GridView.GridViewScrollViewerStyleKey}" TargetType="{x:Type ScrollViewer}">
    			<Setter Property="Focusable" Value="false"/>
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="{x:Type ScrollViewer}">
    						<Grid SnapsToDevicePixels="true" Background="{TemplateBinding Background}">
    							<Grid.ColumnDefinitions>
    								<ColumnDefinition Width="*"/>
    								<ColumnDefinition Width="Auto"/>
    							</Grid.ColumnDefinitions>
    							<Grid.RowDefinitions>
    								<RowDefinition Height="*"/>
    								<RowDefinition Height="Auto"/>
    							</Grid.RowDefinitions>
    							<DockPanel Margin="{TemplateBinding Padding}">
    								<ScrollViewer Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" DockPanel.Dock="Top">
    									<GridViewHeaderRowPresenter Margin="2,0,2,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" AllowsColumnReorder="{Binding Path=TemplatedParent.View.AllowsColumnReorder, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContainerStyle="{Binding Path=TemplatedParent.View.ColumnHeaderContainerStyle, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderContextMenu="{Binding Path=TemplatedParent.View.ColumnHeaderContextMenu, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplate="{Binding Path=TemplatedParent.View.ColumnHeaderTemplate, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderTemplateSelector="{Binding Path=TemplatedParent.View.ColumnHeaderTemplateSelector, RelativeSource={RelativeSource TemplatedParent}}" ColumnHeaderToolTip="{Binding Path=TemplatedParent.View.ColumnHeaderToolTip, RelativeSource={RelativeSource TemplatedParent}}" Columns="{Binding Path=TemplatedParent.View.Columns, RelativeSource={RelativeSource TemplatedParent}}"/>
    								</ScrollViewer>
    								<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}" KeyboardNavigation.DirectionalNavigation="Local"/>
    							</DockPanel>
    							<ScrollBar Cursor="Arrow" x:Name="PART_HorizontalScrollBar" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Grid.Row="1" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0.0" Value="{Binding Path=HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
    							<ScrollBar Cursor="Arrow" x:Name="PART_VerticalScrollBar" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Grid.Column="1" Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0.0" Value="{Binding Path=VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
    							<DockPanel Grid.Column="1" Grid.Row="1" Background="{Binding Path=Background, ElementName=PART_VerticalScrollBar}" LastChildFill="false">
    								<Rectangle Fill="White" Width="1" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" DockPanel.Dock="Left"/>
    								<Rectangle Fill="White" Height="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" DockPanel.Dock="Top"/>
    							</DockPanel>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<Style x:Key="ListViewStyle1" TargetType="{x:Type ListView}">
    			<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
    			<Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
    			<Setter Property="BorderThickness" Value="1"/>
    			<Setter Property="Foreground" Value="#FF042271"/>
    			<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    			<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    			<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
    			<Setter Property="VerticalContentAlignment" Value="Center"/>
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="{x:Type ListView}">
    						<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" RenderMouseOver="{TemplateBinding IsMouseOver}">
    							<ScrollViewer Style="{DynamicResource {x:Static GridView.GridViewScrollViewerStyleKey}}" Padding="{TemplateBinding Padding}">
    								<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
    							</ScrollViewer>
    						</Microsoft_Windows_Themes:ListBoxChrome>
    						<ControlTemplate.Triggers>
    							<Trigger Property="IsGrouping" Value="true">
    								<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
    							</Trigger>
    							<Trigger Property="IsEnabled" Value="false">
    								<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
    							</Trigger>
    						</ControlTemplate.Triggers>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
    			<VirtualizingStackPanel IsItemsHost="True"/>
    		</ItemsPanelTemplate>
    	</Window.Resources>
    
    	<Grid x:Name="LayoutRoot">
    		<ListView Style="{DynamicResource ListViewStyle1}" ItemsPanel="{DynamicResource ItemsPanelTemplate1}">
    			<ListView.View>
    				<GridView>
    					<GridViewColumn/>
    					<GridViewColumn/>
    				</GridView>
    			</ListView.View>
    		</ListView>
    	</Grid>
    </Window>

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年6月15日 18:34
  • DisplayMemberBinidngのみを指定で可能にするのは、すごく挑み概がありそうな感じですね…。
    私はギブアップです^^;

    代替案としてListViewのResourcesに以下のようなStyleを登録しておくのは駄目ですか・・・?
    <Style TargetType="{x:Type TextBlock}">
    	<Setter Property="TextTrimming" Value="CharacterEllipsis" />
    	<Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Self}}" />
    </Style>
    

    (全部の項目に適用されてしまいますが)

    出来ればCellTemplateが駄目な理由とかを教えてもらえると、何かもっといい方法があるかもしれません。
    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年6月16日 8:19
  • えむナウ様
    ご返信ありがとうございます。

     ItemsPanelTemplate という切り口は思いつきませんでした。
    当方技術が不足しておりまして、すぐには理解できないのですが、この切り口で少し試してみようと思います。
    koki
    2009年6月18日 15:08
  • かずき様

    ご返信ありがとうございます。

    Styleで設定してみたところ、
    ListViewItemの中のTextBlockには、設定したStyleが適用されませんでした。
    Windowの上に貼ったTextBlockには適用されたのですが、ListViewItemまで届かないようです。
    WindowのResourceに定義しています。

    >出来ればCellTemplateが駄目な理由とかを教えてもらえると、何かもっといい方法があるかもしれません。
    申し訳ございません。訳あってその理由は明かせないのです。

    しかしながら、Styleを丸ごと変えるという原点回帰とも言うべき発想、ありがとうございました。
    XAMLはハマルととことん違う方向へ行く気がします。

    かずき様のように、Simple is bestな方法が一番良いですね。

    もう少し頑張ってみます。

    koki
    2009年6月18日 15:12
  • ListViewのResourceに追加したときは動いた気がします。
    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年6月18日 16:04
  • ListViewのResourceに追加したときは動いた気がします。
    かずき Blog:http://blogs.wankuma.com/kazuki/

    自分で書いておいて、そんな馬鹿なって思ったので確認してみたのですが、WindowでもListViewでもResourcesにいれておけば大丈夫でした。
    ListView全体は下のような感じです。

    <ListView ItemsSource="{Binding People}">
        <ListView.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="TextTrimming" Value="CharacterEllipsis" />
                <Setter Property="ToolTip" Value="{Binding Text, RelativeSource={RelativeSource Self}}" />
            </Style>
        </ListView.Resources>
        <ListView.View>
            <GridView>
                <GridViewColumn Header="なまえ" DisplayMemberBinding="{Binding Name}" />
            </GridView>
        </ListView.View>
    </ListView>
    

    Nameプロパティを持つだけのクラスのリストをItemsSourceにバインドして表示させています。
    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年6月18日 22:08
  • かずき様

    昨日の夜、やってみたときは駄目だったのですが、
    今日のお昼にやってみたらかずき様の方法で出来ました(笑
    ユメでも見ていたのでしょうか・・・。
    ありがとうございます。

    もうひとつだけ質問させてください。

    上記のListViewをカスタムコントロールとして作成した場合、
    Generic.xamlのStyleのResource内に、TextBlockのStyleを定義したのに、
    反映されませんでした。

    このような場合はどうすればよいかご存知でしょうか?

    おんぶにだっこで大変申し訳ございませんが、よろしくお願いいたします。
    koki
    2009年6月19日 12:36
  • kokiさんの、やろうとしてるやり方で私も色々試してみたのですが現時点で出来ませんでしたorz
    代わりといっては何ですが、添付プロパティあたりをちょっといじくって簡単に適用できるようなものを
    作ってみました。

    私のBlogで恐縮なのですが、以下のエントリにコードとかをのせています。
    http://blogs.wankuma.com/kazuki/archive/2009/06/23/176419.aspx


    かずき Blog:http://blogs.wankuma.com/kazuki/
    • 回答としてマーク Koki Shimizu 2009年6月23日 16:06
    2009年6月23日 14:20
  • かずき様

    いろいろとご親切にありがとうございます。
    まさかサンプルコードまで載せていただけるとは、感謝です。

    私のほうでもいろいろ試した結果、
    DisplayMemberBindingが指定されたあと、
    ListViewItemをほじってTextBlockをBindingするコードをC#で書いたところ、
    カスタムコントロールでもうまく動作することができました。
    コード的には少し汚いですが。。。

    WindowsVistaのエクスプローラは標準のListViewを使っているのではないのですかね?
    そのあたりもMS公開してくれたらなぁ、と思います。
    koki
    2009年6月23日 16:10
  • そのやり方教えてもらってもいいですか~?

    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年6月24日 10:37
  • はい、かずき様、以下のようになります。

    列のCellTemplateに、以下のメソッドの戻り値を入れます。
    TextBlockExは、TextBlockを必ず...表示するカスタムコントロールとします。

    private DataTemplate CreateTenTenTenTemplate(string DisplayMemberBinding)
    {
                DataTemplate cellTemplate = new DataTemplate { DataType = typeof(TextBlockEx) };
                Binding bind = new Binding();
                bind.Path = new PropertyPath(DisplayMemberBinding);
                FrameworkElementFactory tFactory = new FrameworkElementFactory(typeof(TextBlockEx));
                tFactory .SetBinding(TextBlockEx.TextProperty, bind);
                cellTemplate.VisualTree = tFactory ;
                return cellTemplate;
    }

    ここでのミソは、PropertyPathをnewしていることですね。これのC#での書き方がわからず困っていました。
    これにより、動的に(プログラム実行時に)バインディングパスを変更することができます。
    koki
    2009年6月26日 9:18
  • ふむ。
    XAMLからの指定は駄目で、コードからはDataTemplate差し替えるのは
    別にかまわないんですね~。
    かずき Blog:http://blogs.wankuma.com/kazuki/
    2009年6月26日 10:27