简体   繁体   English

如何在StackPanel或ListView中叠加项目?

[英]How to overlay items in StackPanel or ListView?

I am making a card game and I want to display cards in player's hand half-covered be each other. 我正在制作一个纸牌游戏,我想在玩家的手中显示半张相互覆盖的牌。 How can I do that using ListView or StackPanel? 我怎么能用ListView或StackPanel做到这一点? Here is an example how I would like to display player hand. 这是一个如何显示玩家手牌的示例。

球员手

<Grid Background="Green" >
        <Image x:Name="One" Width="100" Height="100" Margin="10,10,250,210"/>
        <Image x:Name="Two" Width="100" Height="100" Margin="10,10,210,210"/>
</Grid>

UPDATE UPDATE

I set margins for ListView's ItemContainerStyle and it worked, but I have another problem. 我为ListView的ItemContainerStyle设置了边距并且它有效,但我有另一个问题。 Width of ListView items doesn't fit the image and there is some spacing. ListView项目的宽度不适合图像,并且有一些间距。 How do I remove that. 我该如何删除它。 See image below the XAML code. 请参阅XAML代码下方的图像。

<ListView Grid.Row="0" Grid.Column="0">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Margin" Value="0, 0, -80, 0"></Setter>
                <Setter Property="Height" Value="100"></Setter>
                <Setter Property="Width" Value="100"></Setter>
            </Style>
        </ListView.ItemContainerStyle>
        <Image x:Name="One" MaxWidth="100" Height="100" />
        <Image x:Name="Two" MaxWidth="100" Height="100" />
    </ListView>

玩家的手

I would use Canvas in the list, and draw your card to the canvas, because things drawn in a canvas are not clipped, and instead managed through the canvas ZIndex etc. 我会在列表中使用Canvas,并将您的卡绘制到画布上,因为画布中绘制的内容不会被剪裁,而是通过画布ZIndex等进行管理。

Size the canvas based on your desired spacing, and oversize the contents. 根据所需间距调整画布大小,并使内容过大。 I'd also recommend binding to Items-source when using listboxes and using templates. 我还建议在使用列表框和使用模板时绑定到Items-source。

BTW I'm defining my cards using solidColorBrushes so I can just draw rectangles, replace this with your image source. 顺便说一下,我使用solidColorBrushes定义我的卡片,所以我可以绘制矩形,用你的图像源替换它。 I've defined my source in the resources, but in reality it would be bound to an ObservableCollection (Say, PlayersCurrentHand or something): 我已经在资源中定义了我的源代码,但实际上它将绑定到ObservableCollection(Say,PlayersCurrentHand等):

<UserControl.Resources>
    <x:Array Type="{x:Type SolidColorBrush}" x:Key="Cards">
        <SolidColorBrush Color="Blue"/>
        <SolidColorBrush Color="Red"/>
        <SolidColorBrush Color="White"/>
        <SolidColorBrush Color="White"/>
        <SolidColorBrush Color="White"/>
        <SolidColorBrush Color="White"/>
    </x:Array>
</UserControl.Resources>

Now, I presume you are using ListBox because you want to support selection? 现在,我认为你正在使用ListBox,因为你想支持选择? If so, the way WPF highlights list box items will mess up with this overlap, so we will need to replace it. 如果是这样,WPF突出显示列表框项的方式会搞乱这种重叠,所以我们需要替换它。 If you don't want selection, just use an itemsControl and you can skip all the selection stuff. 如果您不想选择,只需使用itemsControl,您就可以跳过所有选择内容。

Here's our basic listbox: 这是我们的基本列表框:

<ListView ItemsSource="{StaticResource Cards}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="112,98,-325,-25" Width="513" Height="227">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" IsItemsHost="True" VerticalAlignment="Top"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="1">
                <Rectangle Fill="{Binding}" Width="60" Height="100"/>
            </Border>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Which gives us this: 这给了我们这个:

在此输入图像描述

Now, we want to have all the list items to be drawn in a canvas, so let's define our ItemContainerStyle: 现在,我们想要在画布中绘制所有列表项,所以让我们定义ItemContainerStyle:

    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListViewItem}">
                        <StackPanel>
                            <Canvas Width="15" Height="100">
                                <ContentPresenter />
                            </Canvas>
                        </StackPanel>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListView.ItemContainerStyle>

See how we've set the canvas Width to 15? 看看我们如何将画布宽度设置为15? That defines the spacing of our cards. 这定义了我们卡片的间距。 All the canvases are stacked at intervals of 15. However, the Rectangles we are drawing in our DateTemplate is Width 60, so these spill off to the right. 所有画布都以15的间隔堆叠。但是,我们在DateTemplate中绘制的矩形宽度为60,因此这些矩形向右溢出。

在此输入图像描述

We've overridden the messy standard selection and highlighting styles. 我们已经超越了凌乱的标准选择和突出风格。 But no we don't know what's highlighted and selected, so let's add some functionality back in. We can also add things like shadows etc: 但不,我们不知道突出显示和选择了什么,所以让我们重新添加一些功能。我们还可以添加阴影等内容:

<ControlTemplate TargetType="{x:Type ListViewItem}">
    <StackPanel>
        <Canvas Width="15" Height="100">
            <Rectangle x:Name="Highlight"  Width="60" Height="5" Canvas.Top="105"/>
            <Rectangle Fill="#50000000" Width="60" Height="100" Margin="5,0,-5,0"/>
            <ContentPresenter />
        </Canvas>
    </StackPanel>
    <ControlTemplate.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter TargetName="Highlight" Property="Fill" Value="Yellow"/>
        </Trigger>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Panel.ZIndex" Value="99"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

So now we have this: 所以现在我们有了这个:

在此输入图像描述

Note, the gif didn't render the selection exactly right. 注意,gif没有完全正确地选择。 The width issue is going to be tricky to fix without some code behind I think. 如果没有一些代码,我认为宽度问题很难修复。 One option is to make an IValueConverter that calculates width given the List of cards, and binding it to the Listview's Width property. 一种选择是制作一个IValueConverter,它计算卡片列表的宽度,并将其绑定到Listview的Width属性。

Edit 编辑

Found a way to get around the size issue! 找到了解决尺寸问题的方法! Padding! 填充! Of course. 当然。 However, I found the scroll viewer clips even the canvas it contains (which makes sense if you think about it) but leaves all our effort hidden: 但是,我发现滚动查看器甚至剪辑它所包含的画布(如果你考虑它就有意义)但是我们把所有的努力隐藏起来:

在此输入图像描述

So you have to overwrite the scroll viewer functionality by setting the ControlTemplate manually: 因此,您必须通过手动设置ControlTemplate来覆盖滚动查看器功能:

    <ListBox.Template>
        <ControlTemplate>
            <Border Padding="5,25,55,15" BorderBrush="Gray" BorderThickness="1">
                <ItemsPresenter />
            </Border>
        </ControlTemplate>
    </ListBox.Template>

So now the padding accounts for the last card sticking out an extra 50. 所以现在padding占了最后一张额外50张卡。

Total code, with some more visual tweaks: 总代码,有一些更多的视觉调整:

<ListView ItemsSource="{StaticResource Cards}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20" BorderBrush="Black">
    <ListBox.Template>
        <ControlTemplate>
            <Border Padding="5,25,55,15" BorderBrush="Gray" BorderThickness="1">
                <ItemsPresenter />
            </Border>
        </ControlTemplate>
    </ListBox.Template>
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" IsItemsHost="True" ClipToBounds="False" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListViewItem}">
                        <StackPanel>
                            <Canvas Width="15" Height="100">
                                <Rectangle x:Name="Highlight"  Width="60" Height="5" Canvas.Top="105"/>
                                <ContentPresenter x:Name="CardPresenter"/>
                            </Canvas>
                        </StackPanel>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Panel.ZIndex" Value="99"/>
                                <Setter TargetName="CardPresenter" Property="Canvas.Top" Value="-5"/>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter TargetName="Highlight" Property="Fill" Value="Yellow"/>
                                <Setter TargetName="CardPresenter" Property="Canvas.Top" Value="-20"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Border Background="#60000000" BorderThickness="0" CornerRadius="5" Height="100" Margin="5,0,-5,0"/>
                <Border BorderBrush="Black" BorderThickness="1" CornerRadius="5" Background="{Binding}" Width="60" Height="100"/>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

在此输入图像描述

It's pretty flexible, it was easy to add the "sticking out" functionality. 它非常灵活,很容易添加“伸出”功能。 Animations would be the next big step. 动画将是下一个重要的步骤。

Edit 2 编辑2

I'm just playing now. 我现在才玩。 I'm not sure I like the "jump to the front" functionality, would be better if they just peeked out. 我不确定我喜欢“跳到前面”功能,如果他们只是偷看会更好。 Also, fanning them out (using a multi-binding): 另外,将它们扇出(使用多重绑定):

在此输入图像描述

Using the following template: 使用以下模板:

<ControlTemplate TargetType="{x:Type ListViewItem}">
    <StackPanel>
        <Canvas Width="15" Height="100">
            <Rectangle x:Name="Highlight"  Width="60" Height="5" Canvas.Top="105"/>
            <ContentPresenter x:Name="CardPresenter">
                <ContentPresenter.RenderTransform>
                    <TransformGroup>
                        <TranslateTransform x:Name="TranslateTransformHighlight"/>
                        <RotateTransform x:Name="RotateTransformHighlight" CenterY="100"/>
                        <TranslateTransform x:Name="TranslateTransformSelect"/>
                    </TransformGroup>
                </ContentPresenter.RenderTransform>
            </ContentPresenter>
        </Canvas>
    </StackPanel>
    <ControlTemplate.Triggers>
        <Trigger Property="IsMouseOver" Value="True" >
            <Trigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="TranslateTransformHighlight" Duration="0:0:0.200" To="-5" Storyboard.TargetProperty="Y" />
                        <DoubleAnimation Storyboard.TargetName="RotateTransformHighlight" Duration="0:0:0.200" To="-5" Storyboard.TargetProperty="Angle" />
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="TranslateTransformHighlight" Duration="0:0:0.200" To="0" Storyboard.TargetProperty="Y" />
                        <DoubleAnimation Storyboard.TargetName="RotateTransformHighlight" Duration="0:0:0.200" To="0" Storyboard.TargetProperty="Angle" />
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.ExitActions>
        </Trigger>
        <Trigger Property="IsSelected" Value="True">
            <Setter TargetName="Highlight" Property="Fill" Value="Yellow"/>
            <Trigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="TranslateTransformSelect" Duration="0:0:0.200" To="-15" Storyboard.TargetProperty="Y" />
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.EnterActions>
            <Trigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="TranslateTransformSelect" Duration="0:0:0.200" To="0" Storyboard.TargetProperty="Y" />
                    </Storyboard>
                </BeginStoryboard>
            </Trigger.ExitActions>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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