Home > Enterprise >  wpf xaml binding to translateTransform in Resource
wpf xaml binding to translateTransform in Resource

Time:02-03

I have a path defined as a resource in a resourceDictionary. In the code a rectangle with a transformgroup is defined. There are a few transforms to position the rectangle at a local datum then a translateTransform with a binding.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <GeometryGroup x:Key="box">
        <RectangleGeometry Rect="0,0,70,25"/>
        <GeometryGroup.Transform>
            <TransformGroup>
                <ScaleTransform ScaleX="1" ScaleY="1"/>
                <TranslateTransform X="-37.5" Y="-12.5"/>
                <TranslateTransform X="500" Y="0"/>
                <RotateTransform Angle="0"/>
                <TranslateTransform X="{Binding BX}" Y="{Binding BY}"/>
            </TransformGroup>
            
        </GeometryGroup.Transform>
    </GeometryGroup>
</ResourceDictionary>

The viewmodel holds an observable collection of "box" objects. Each box object has a BX and BY property to define the position of the box. The xaml page displays those boxes.

There is a data template as shown here which points to the resource:

<DataTemplate DataType="{x:Type cfg:Box}">
    <Path Fill="White" Stroke="Black" Data="{StaticResource box}"/>
</DataTemplate>

Currently the boxes are displayed on a canvas with the following code:

<ItemsControl ItemsSource="{Binding Boxes}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=BX}"/>
            <Setter Property="Canvas.Top"  Value="{Binding Path=BY}"/>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

This does locate the shapes on the canvas by setting the Canvas.Left and Canvas.Top properties. But instead what I would like to do is bind the BX and BY values from each "box" object in the observablecollection to the translateTransform associated with each item that is bound to the itemssource. (Right now the binding in the resource's translatetransform fails.)

So if I have 5 boxes in my observablecollection in the view model, and each one has a unique position in a BX and BY property (with an option to rotate, scale, etc) - how do I bind those properties to the corresponding items in the ItemsControl?

CodePudding user response:

I don't follow why binding the contentpresenter canvas.left and top is not suitable.

Any bindings on properties in your geometrygroup cannot work as you have it in a resource dictionary.

Geometrygroup is a freezable and will be frozen if you put it in a resource dictionary. There is a built in mechanism calls Freeze() on any and all freezables you use in a resource dictionary. That means those variables aren't going to change.

https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.geometrygroup?view=windowsdesktop-7.0

Inheritance: Object DispatcherObject DependencyObject Freezable Animatable Geometry GeometryGroup

You could put your geometrygroup in windows resources instead and it wouldn't be frozen.

The translatetransform has an Xproperty and Yproperty which I've animated in the past so I think the binding could work if there's a suitable BX and BY property in the datacontext of the resource.

You should be able to do something like:

    <Style TargetType="ContentPresenter">
        <Setter Property="RenderTransform">
            <Setter.Value>
                <TransformGroup>
                    <RotateTransform x:Name="RotateTransform"
                             Angle="{Binding Angle}"
                             CenterX="{Binding CenterX}"
                             CenterY="{Binding CenterY}"/>
                    <ScaleTransform x:Name="MirrorTransform"
                                    ScaleX="{Binding MirroringX}"
                                    ScaleY="{Binding MirroringY}"
                                    CenterX="{Binding CenterX}"
                                    CenterY="{Binding CenterY}"/>
                    <ScaleTransform x:Name="ScaleTransform"
                                    ScaleX="{Binding ScaleX}"
                                    ScaleY="{Binding ScaleY}"/>
                </TransformGroup>
            </Setter.Value>
        </Setter>
    </Style>
</ItemsControl.ItemContainerStyle>

So long as you don't get your transform frozen by putting it in a resource dictionary.

  • Related