Jonathan Tuzman
Jonathan Tuzman

Reputation: 13262

ZIndex for one canvas over an adjacent canvas

I'm trying to render a row of interlocking arrows, like this:

enter image description here

Each arrow represents a step in a workflow, and the color of each arrow is determined by its step's position in the workflow. While the example above has 3 colors (before, current, after), so far I've implemented only 2 colors (before/current, after) and that's fine for the purposes of this question. I've got an IMultiValueConverter to handle those colors.

The workflow steps are represented as a StepStruct which has a Step property (set manually, more on this later), and a VmFunc property which returns the view model for that step. My current IMultiValueConverter uses the index of the step in the list of steps, rather than the actual Step value.

My problem is the arrows. Initially I have each step as a canvas rendering a simple rectangle, and that's easy to get working. But to make the arrow, I've used a PolyLine that I want to position at the right of the canvas, indeed starting at the right of one canvas and overflowing into the next.

I can't get the Panel.ZIndex to work in such a way that a canvas's arrow is visible overflowing into its right-hand neighbor.

My code is pasted below. Of note:

<Border Grid.Row="0" BorderBrush="{StaticResource BackgroundBlack}" BorderThickness="2">

    <!--Progress bar-->
    <ItemsControl ItemsSource="{Binding StepViewModels}" Grid.Row="0" x:Name="progressBar">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Rows="1"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Canvas Height="24">
                    <Canvas.Style>
                        <Style TargetType="Canvas">
                            <Setter Property="Background" Value="{StaticResource BackgroundDarkGrey}"/>

                            <Style.Triggers>
                                <DataTrigger>
                                    <DataTrigger.Binding>
                                        <!-- the binding. this part works so I'm omitting the code -->
                                    </DataTrigger.Binding>
                                    <DataTrigger.Value>True</DataTrigger.Value>
                                    <Setter Property="Background" Value="{StaticResource DisabledGrey}"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Canvas.Style>

                    <Polyline Points="0,-1 20,11 0,25" Stroke="{StaticResource BackgroundBlack}" StrokeThickness="2" 
                            Fill="{Binding Background, RelativeSource={RelativeSource AncestorType=Canvas}}"
                            Panel.ZIndex="{Binding Step}"
                            />
                    <!--Canvas.Left="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Canvas}}"-->

                    <TextBlock Text="{Binding Step}" FontWeight="ExtraBlack" Panel.ZIndex="40" Foreground="Pink" FontSize="20" Canvas.Left="8"/>
                </Canvas>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Border>

The result (with the Canvas.Left still commented) enter image description here

How do I get the arrows to render at the end of one canvas and atop the next, as desired?

(I could of course keep it this way and make it work but the bindings would be very annoying and complicated, needing to bind each arrow to the color of the previous canvas; or rather do some kind of conversion involving IndexOf - 1)

Upvotes: 0

Views: 97

Answers (1)

o_w
o_w

Reputation: 683

For ZIndex:

Each item is wrapped by a ContentPresenter, this is done by the ItemContainerGenerator inside this ItemsControl instance.

So you need to edit the container to get a new ZIndex(via a ContentPresenter style and a binding for example).

<ItemsControl.ItemContainerStyle>
    <Style TargetType="ContentPresenter">
        <Setter Property="Panel.ZIndex" Value="{Binding XXX}" />
    </Style>
</ItemsControl.ItemContainerStyle>

For the shape:

I would recommend using a Path control with a predefined shape geometry like:

"M 0,0 L30,0 L34,5 L30,10 L0,10 z"

and have a negative margin at the end like Margin="0,0,-4,0"

Upvotes: 2

Related Questions