set each item's z-index in Grid.ItemsControl

425 views Asked by At
    <DataTemplate x:Key="DataTemplateMusicControl">
        <uc:MusicControl Canvas.ZIndex="2" Style="{StaticResource ModelStyle}"></uc:MusicControl>
    </DataTemplate>
    <DataTemplate x:Key="DataTemplateImageControl">
        <uc:ImageControl Canvas.ZIndex="2"></uc:ImageControl>
    </DataTemplate>
    <DataTemplate x:Key="DataTemplateLoginControl">
        <uc:LoginControl Canvas.ZIndex="1"></uc:LoginControl>
    </DataTemplate>
    <DataTemplate x:Key="DataTemplateTextControl">
        <uc:TextEditControl> </uc:TextEditControl>
    </DataTemplate>
    <local:ModelDataTemplateSelector x:Name="MyTemplateSelector" 
                                     DataTemplateMusicControl="{StaticResource DataTemplateMusicControl  }" 
                                     DataTemplateImageControl="{StaticResource DataTemplateImageControl}"
                                     DataTemplateLoginControl="{StaticResource DataTemplateLoginControl}"/>

    <ItemsControl ItemsSource="{Binding GridItemList}"
                ItemTemplateSelector="{StaticResource MyTemplateSelector}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate >
                <Canvas Name="MainCanvas" Background="#FFB85252"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

I was trying to set the z-index in my each model, but failed.

Define a datatemplate as above, I have been set Z-index property, but come always up above item that was added last.

any ideas?

1

There are 1 answers

0
Rob Caplan - MSFT On BEST ANSWER

Canvas.ZIndex and similar attached properties affect the element's position in its parent Canvas, but in your case the Canvas isn't the parent of the items. There is a ContentPresenter between the Canvas and the template's root UserElement (uc:ImageControl, etc.).

We can't set properties on the ContentPresenter directly from the Xaml. We'll need to duck into the code-behind and subclass the ItemsControl so we can override the containers as they are created:

class ZIndexItemsControl : ItemsControl
{
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);
        FrameworkElement source = element as FrameworkElement;
        source.SetBinding(Canvas.ZIndexProperty, new Binding { Path = new PropertyPath("ZIndex") });
        // source.SetValue(Canvas.ZIndexProperty, 2);
        source.SetBinding(AutomationProperties.AutomationIdProperty, new Binding { Path = new PropertyPath("AutomationId") });
        source.SetBinding(AutomationProperties.NameProperty, new Binding { Path = new PropertyPath("AutomationName") });
    }
}

This code snippet sets up a binding from the container's Canvas.ZIndexProperty to the data object's ZIndex property, but you can point the ZIndex elsewhere or set it directly as needed.

It also binds the AutomationProperties to properties on the data object so the app doesn't default to calling the object's ToString (not a problem for simple objects which can set ToString to something reasonable, but probably not good enough for a complex object). Listen to your app in Narrator to see how it sounds.