简体   繁体   中英

How to make WPF ListView horizontal with contained image stretched to fit the height?

I want a gallery that shows images with labels in a horizontal ListView .

Each list item is merely an image with a label:

<DataTemplate x:Key="ImageItemTemplate">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="4*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Image Grid.Row="0" Source="{Binding Image}" Stretch="UniformToFill" />
        <Label Grid.Row="1" Content="{Binding Title}" />
    </Grid>
</DataTemplate>

To make the ListView horizontal, I replace the ListView.ItemsPanel with a horizontal StackPanel :

<ListView.ItemsPanel>
    <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>
</ListView.ItemsPanel>

Now I got something like this:

初始状态

But I want each image to stretch to take the full height of the ListView (minus enough height for the label), while maintaining the aspect ratio, so I replace the ListView.ItemContainerStyle :

<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem">
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Stretch" />
    </Style>
</ListView.ItemContainerStyle>

But I have no idea why the width of each item is not stretched but instead cut:

拉伸状态

Please help, thanks!

EDIT:

The whole xaml is shown as follows:

<UserControl x:Class="Test.ImageGalleryControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        mc:Ignorable="d">
    <UserControl.Resources>
        <DataTemplate x:Key="ImageItemTemplate">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="4*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Image Grid.Row="0" Source="{Binding Image}" Stretch="UniformToFill" />
                <Label Grid.Row="1" Content="{Binding Title}" />
            </Grid>
        </DataTemplate>
    </UserControl.Resources>

    <Grid>
        <ListView x:Name="MyImageList" ItemTemplate="{StaticResource ImageItemTemplate}">
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                    <Setter Property="VerticalContentAlignment" Value="Stretch" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
        </ListView>
    </Grid>
</UserControl>

Try this

by setting ListView height to Itemtemplate (grid).

<ListView  x:Name="MyImageList">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch" />
            <Setter Property="VerticalContentAlignment" Value="Stretch" />
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Height="{Binding ElementName=MyImageList,Path=ActualHeight}">
                <Grid.RowDefinitions>
                    <RowDefinition Height="4*" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <Image Grid.Row="0" Source="Screenshot_3.png" Stretch="UniformToFill" />
                <Label Grid.Row="1" Content="fghfgh" />
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Update

by setting VerticalScrollBarVisibility="Hidden" or disabled and adding margin you can solve this problem but proper solution is below

this verticalscrollbar is coming due to default margin and padding in Listview and ListviewItem default style..you can achieve desired result by editing style of listview and listviewItem

working sample(without vertical scrollbar)

Resource

<Window.Resources>
    <Style TargetType="{x:Type ListView}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="#FFABADB3"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
        <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
        <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
        <Setter Property="ScrollViewer.PanningMode" Value="Both"/>
        <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListView}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" Height="{TemplateBinding Height}" BorderThickness="0" Background="{TemplateBinding Background}" Padding="0" SnapsToDevicePixels="True">
                        <ScrollViewer Focusable="False" Padding="0" >
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </ScrollViewer>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="Background" TargetName="Bd" Value="White"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="#FFD9D9D9"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsGrouping" Value="True"/>
                                <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="False"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="ScrollViewer.CanContentScroll" Value="False"/>
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="{x:Type ListViewItem}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}"/>
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderBrush" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="FocusVisualStyle">
            <Setter.Value>
                <Style>
                    <Setter Property="Control.Template">
                        <Setter.Value>
                            <ControlTemplate>
                                <Rectangle Margin="2" SnapsToDevicePixels="True" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListViewItem}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1"  Background="{TemplateBinding Background}" Margin="0,-1,5,-1" SnapsToDevicePixels="True">
                        <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsMouseOver" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="#1F26A0DA"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="#A826A0DA"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="False"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="#3DDADADA"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="#FFDADADA"/>
                        </MultiTrigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="True"/>
                                <Condition Property="IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="#3D26A0DA"/>
                            <Setter Property="BorderBrush" TargetName="Bd" Value="#FF26A0DA"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

window

<ListView  x:Name="MyImageList">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <Grid Height="{Binding ElementName=MyImageList,Path=ActualHeight}">
        <Grid.RowDefinitions>
            <RowDefinition Height="4*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Image Grid.Row="0" Source="Screenshot_3.png" Stretch="UniformToFill" />
        <Label Grid.Row="1" Content="fghfgh"/>
    </Grid>
    <Grid  Height="{Binding ElementName=MyImageList,Path=ActualHeight}">
        <Grid.RowDefinitions>
            <RowDefinition Height="4*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Image Grid.Row="0" Source="Screenshot_3.png" Stretch="UniformToFill" />
        <Label Grid.Row="1" Content="fghfgh"/>
    </Grid>
</ListView>

Try now to change the stretch property. Hmm, can't add the code somewhy...

try setting Stretch="Uniform" to the image

<Image Grid.Row="0" Source="{Binding Image}" Stretch="Uniform" />
<Image Grid.Row="0" Source="{Binding Image}" Stretch="Fill" />

but, it will not maintain the aspect ratio of the image, Use Stretch="Uniform" to keep the aspect ratio regardless the size of the image control. You can statically specify the Height of the image control and use Stretch="Uniform" to adjust both aspect ratio and the size of the image control.

a simple solution using ItemsControl

<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="ImageItemTemplate">
            <Grid Height="{Binding ActualHeight,RelativeSource={RelativeSource FindAncestor,AncestorType=ItemsControl}}"
                  Margin="2,2,2,-25"
                  VerticalAlignment="Top">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition Height="auto" />
                </Grid.RowDefinitions>
                <Image Grid.Row="0" Source="{Binding Image}" Stretch="UniformToFill" />
                <Label Grid.Row="1" Content="{Binding Title}" />
            </Grid>
        </DataTemplate>
    </Grid.Resources>
    <ScrollViewer HorizontalScrollBarVisibility="Auto"
                  VerticalScrollBarVisibility="Hidden">
        <ItemsControl x:Name="MyImageList"
                      ItemTemplate="{StaticResource ImageItemTemplate}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </ScrollViewer>
</Grid>

"a simple solution using ItemsControl" by @pushpraj really helped me after a prolonged search for a similar feature. I'm new to WPF but still tried with ListView and Ribbon with ItemsControl templates, but didnt get the result that I wanted. A small alteration to fit my requirement, I made the Image stretch to uniform, Stretch="Uniform". Thanks for the blog.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM