如何在StackPanel或ListView中叠加项目? [英] How to overlay items in StackPanel or ListView?

查看:91
本文介绍了如何在StackPanel或ListView中叠加项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作纸牌游戏,我想在玩家的手半张盖的情况下互相显示纸牌.如何使用ListView或StackPanel做到这一点?这是我想要显示玩家手形的示例.

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? 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>

更新

我为ListView的ItemContainerStyle设置了页边距,它起作用了,但是还有另一个问题. ListView项的宽度不适合图像,并且存在一些间距.我该如何删除.参见XAML代码下方的图片.

I set margins for ListView's ItemContainerStyle and it worked, but I have another problem. Width of ListView items doesn't fit the image and there is some spacing. How do I remove that. See image below the XAML code.

<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>

推荐答案

我会在列表中使用Canvas,并将卡片绘制到画布上,因为在画布中绘制的内容不会被裁剪,而是通过画布ZIndex进行管理等

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.

根据您想要的间距调整画布的尺寸,并扩大内容的尺寸.我还建议在使用列表框和模板时绑定到Items-source.

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.

顺便说一句,我正在使用solidColorBrushes定义卡片,因此我可以绘制矩形,并用您的图像源替换它.我已经在资源中定义了我的源,但实际上它将绑定到一个ObservableCollection(例如,PlayersCurrentHand或其他东西):

BTW I'm defining my cards using solidColorBrushes so I can just draw rectangles, replace this with your image source. I've defined my source in the resources, but in reality it would be bound to an ObservableCollection (Say, PlayersCurrentHand or something):

<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>

现在,我想您正在使用ListBox是因为您要支持选择?如果是这样,WPF突出显示列表框项目的方式将使此重叠变得混乱,因此我们将需要替换它.如果您不想选择,只需使用itemsControl,即可跳过所有选择内容.

Now, I presume you are using ListBox because you want to support selection? If so, the way WPF highlights list box items will mess up with this overlap, so we will need to replace it. If you don't want selection, just use an itemsControl and you can skip all the selection stuff.

这是我们的基本列表框:

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>

哪个给我们的呢?

现在,我们要在画布上绘制所有列表项,所以让我们定义ItemContainerStyle:

Now, we want to have all the list items to be drawn in a canvas, so let's define our 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>

看看我们如何将画布的宽度设置为15?这就定义了我们卡片的间距.所有画布以15的间隔堆叠.但是,我们在DateTemplate中绘制的矩形为Width 60,因此这些溢出到右侧.

See how we've set the canvas Width to 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.

我们已经取代了凌乱的标准选择和突出显示样式.但是,不,我们不知道突出显示和选择了什么,因此让我们重新添加一些功能.我们还可以添加阴影等内容:

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:

请注意,gif无法正确呈现所选内容.我认为如果没有任何代码,就很难解决宽度问题.一种选择是制作一个IValueConverter来计算给定卡片列表的宽度,并将其绑定到Listview的Width属性.

Note, the gif didn't render the selection exactly right. 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.

修改

找到解决尺寸问题的方法!填充!当然.但是,我发现滚动查看器甚至剪辑了其中包含的画布(如果您考虑一下,这都是有道理的),但我们的所有努力都隐藏了:

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:

因此,您必须通过手动设置ControlTemplate来覆盖滚动查看器功能:

So you have to overwrite the scroll viewer functionality by setting the ControlTemplate manually:

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

因此,现在填充会占最后一张卡的额外50张.

So now the padding accounts for the last card sticking out an extra 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.

编辑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):

使用以下模板:

<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>

这篇关于如何在StackPanel或ListView中叠加项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆