简体   繁体   English

在触发器中的父内容演示者上设置ZIndex

[英]Set ZIndex On Parent Content Presenter in a Trigger

I have an ItemsControl which has a Canvas as it's ItemsPanel, the items are simple Borders, the details of the Borders are databound from a view model, data like X,Y Width, Height, Colour etc. I soon realised that even though I could bind most data like the size and colour to the border item itself I had to bind the point data and ZIndex in the ItemsControl Container Style, I believe this is because these properties pertains only to that ItemContainer which is a ContentPresenter: 我有一个具有Canvas的ItemsControl,它是ItemsPanel,这些项目是简单的Borders,Borders的详细信息是来自视图模型的数据绑定,诸如X,Y Width,Height,Color等数据。我很快意识到,即使我可以将大多数数据(如大小和颜色)绑定到边框项目本身,我必须将点数据和ZIndex绑定到ItemsControl容器样式中,我相信这是因为这些属性仅与那个属于ContentPresenter的ItemContainer有关:

<ItemsControl.ItemContainerStyle>
      <Style>
             <Setter Property="Canvas.Left" Value="{Binding Metrics.Ordinate.X}"/>
             <Setter Property="Canvas.Top" Value="{Binding Metrics.Ordinate.Y}"/>
             <Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}"/>
       </Style>
 </ItemsControl.ItemContainerStyle>

Everything has been working as needed up to now. 到目前为止,一切都已按需要进行。 When the user was hovering over the borders I was using a trigger on mouse over to change the background colour but because the UI is already so dependant upon colours we decided that for the hover we wanted the borders to increase in size. 当用户将鼠标悬停在边框上时,我在鼠标悬停时使用触发器来更改背景颜色,但是由于UI已经非常依赖于颜色,因此我们决定为悬停添加边框的大小。 So I added a scale transform instead: 因此,我改为添加了比例转换:

 <Trigger Property="IsMouseOver" Value="True">
     <!--<Setter Property="Background" Value="{Binding SelectedTemplate.StandardBrush}"></Setter>-->
         <Setter Property="LayoutTransform">
               <Setter.Value>
                    <ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
                </Setter.Value>
          </Setter>
 </Trigger>

Now the problem is that I need to increase the ZIndex of that single border in the trigger as well so that as it grows it is not clipped by its nearby fellow items. 现在的问题是,我还需要在触发器中也增加该单个边框的ZIndex,以使它的增长不会被附近的其他对象限制。 I was searching on how to set the parent item (ContentPresenter) in XAML in a trigger and came across this . 我正在搜索如何在触发器中设置XAML中的父项(ContentPresenter)并遇到了这个问题 That looks perfect except that there is no Name on the content presenter to reference it with, it is a repeated control and I cannot fathom how I can reference it within XAML. 看起来很完美,除了内容演示者上没有Name用来引用它之外,它是重复控件,我无法理解如何在XAML中引用它。

Is this possible within a trigger or am I best looking for a different approach, either one not relying solely upon XAML or maybe a change to my ItemsControl? 这是否可以在触发器内实现,还是我最好在寻找一种不同的方法,要么不完全依赖XAML,要么可能对我的ItemsControl进行更改?

Many thanks in advance. 提前谢谢了。

Paul 保罗

Edit 编辑

Adding the panel template: 添加面板模板:

 <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <local:AutoSizeCanvas/>
            </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>

AutoCanvas is a custom control the derives from Canvas which overrides the measure override so it plays ball living inside a scrollviewer, that is the only difference to a standard Canvas. AutoCanvas是自Canvas派生的自定义控件,它覆盖了度量替代,因此它在滚动查看器中打球,这是与标准Canvas的唯一区别。

Edit 编辑

Just to add that I'm using data templates for the bound items as some borders need to contain slightly different items within them, David's current answer below does work, on mouse over the ZIndex is increased, the problem is that all items that are hovered over have their ZIndex increased so if the mouse goes over an item that is meant to be at the back then it is raised to the top, also this seems very slow. 只是要补充一下,我正在为绑定项使用数据模板,因为某些边框需要在其中包含略有不同的项,下面是David的当前答案确实有效,将鼠标悬停在ZIndex上时,问题是所有悬停的项上方的ZIndex增大,因此,如果鼠标悬停在本应位于背面的项目上,则将其提升到顶部,这似乎也很慢。 The solution does work but not quite in this scenario as it is doing a blanket setting on all items, not just the one type of border that needs the trigger. 该解决方案确实有效,但在这种情况下效果不佳,因为它对所有项目进行覆盖设置,而不仅仅是需要触发的一种边框类型。 In essence I have a seating plan which I get the visual data from another application and have to use it as is. 本质上,我有一个座位计划,可以从另一个应用程序获取视觉数据,并且必须按原样使用。 The plan has zones, blocks, rows and seats, It is only the seats that I want this trigger to occur for. 该计划有区域,街区,行和座位,这只是我希望触发此事件的座位。

Hope that's clear. 希望很清楚。

are you sure that you need the ContentPresenter's ZIndex to be increased and not just the Border's ZIndex? 您确定需要增加ContentPresenter的ZIndex而不只是边框的ZIndex吗?

if so, you do not have many options there. 如果是这样,您那里没有太多选择。 The best I can see is to setup the trigger directly in the itemsPresenter's style. 我所看到的最好的方法是直接在itemsPresenter的样式中设置触发器。 This way you don't have to try to find the border's parent (wich I think is impossible to do just in xaml anyway) 这样,您就不必尝试寻找边界的父对象(至此,我认为仅在xaml中是不可能的)

so you'd end up with something like this: 所以你最终会得到这样的东西:

<ItemsControl.ItemContainerStyle>
    <Style>
        <Setter Property="Canvas.Left" Value="{Binding Metrics.Ordinate.X}"/>
        <Setter Property="Canvas.Top" Value="{Binding Metrics.Ordinate.Y}"/>
        <Setter Property="Canvas.ZIndex" Value="{Binding ZIndex}"/>
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="Canvas.ZIndex" Value="1000"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</ItemsControl.ItemContainerStyle>

David's answer is correct for my original question before I provided additional detail and is a perfectly good answer, sadly it did not work in my peculiar scenario. 在我提供更多详细信息之前,David的答案对于我的原始问题是正确的,并且是一个很好的答案,可悲的是,它在我的特殊情况下不起作用。

I managed to solve the problem with code behind for my datatemplate border: 我设法通过为我的datatemplate边框添加代码来解决了这个问题:

The XAML for the template : 模板的XAML:

<DataTemplate DataType="{x:Type vm:Seat}">
    <Border CornerRadius="3" Width="{Binding Metrics.Size.Width}" Height="{Binding Metrics.Size.Height}" BorderThickness="2" MouseEnter="MouseEnter" MouseLeave="MouseLeave">
        <Border.RenderTransform>
            <ScaleTransform x:Name="ZoomTransform" ScaleX="1" ScaleY="1"/>
        </Border.RenderTransform>
        <Border.InputBindings>
            <MouseBinding Gesture="LeftClick" Command="{Binding LeftClickCommand}"/>
            <MouseBinding Gesture="RightClick" Command="{Binding RightClickCommand}"/>
        </Border.InputBindings>
        <Border.Style>
            <Style TargetType="{x:Type Border}">
                <Setter Property="BorderBrush" Value="{Binding PriceBorderColour}"></Setter>
                <Setter Property="Background" Value="{Binding Template.StandardBrush}"></Setter>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsSelected}" Value="True">
                        <Setter Property="Background" Value="{Binding SelectedTemplate.StandardBrush}"/>
                    </DataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding RelativeSource={RelativeSource Mode=Self}, Path=IsMouseOver}" Value="True"/>
                            <Condition Binding="{Binding Plan.EditModel.EditEnabled}" Value="True"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Cursor" Value="Pen"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Border.Style>
        <Viewbox>
            <TextBlock Text="{Binding ObjectLabel.Text}" Foreground="{Binding ObjectLabel.FontColour}"/>
        </Viewbox>
    </Border>
</DataTemplate>

And the Code Behind: 以及后面的代码:

public partial class VisualDataTemplates : ResourceDictionary
{
    private Int32 _originalZIndex;
    private const Double _scaleSize = 1.5;
    private const Double _standardScaleSize = 1;

    public VisualDataTemplates()
    {
        InitializeComponent();
    }

    protected void MouseEnter(Object sender, RoutedEventArgs e)
    {
        Border border = sender as Border;
        ContentPresenter presenter = border.TemplatedParent as ContentPresenter;

        _originalZIndex = Canvas.GetZIndex(presenter);
        Canvas.SetZIndex(presenter, DisplayOrders.FrontItem);

        SetTransform(border, _scaleSize);
    }

    protected void MouseLeave(Object sender, RoutedEventArgs e)
    {
        Border border = sender as Border;
        ContentPresenter presenter = border.TemplatedParent as ContentPresenter;
        Canvas.SetZIndex(presenter, _originalZIndex);

        SetTransform(border, _standardScaleSize);

    }

    private void SetTransform(Border border, Double value)
    {
        ScaleTransform transform = border.RenderTransform as ScaleTransform;
        transform.ScaleX = transform.ScaleY = value;
    }
}

The only problem I have now is that it is slow as hell so I may have to abandon this idea entirely and find another visual effect for the hover. 我现在唯一的问题是它的运行速度很慢,因此我可能不得不完全放弃这个想法,并为悬停找到另一个视觉效果。

If anyone else has any better ideas then please provide. 如果还有其他更好的想法,请提供。

Thanks 谢谢

Paul 保罗

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

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