2
votes

I am using a DataTemplate to add Rectangles to an ItemsControl. The rectangles are specified in an ObservableCollection that is assigned as the ItemsSource of the ItemsControl. The rectangle model specifies translations, rotations and scalings.

What I don't understand: why can I bind something to a transform when Transform or TransformGroup are not FrameworkElements and thus don't support inheriting the DataContext?

The XAML-compiler even gives me errors:

(System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Scale; DataItem=null; target element is 'ScaleTransform' (HashCode=35912612); target property is 'ScaleX' (type 'Double'))

but nevertheless the display of the items works fine. This is weird, isn't it.

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Rectangle Width="100" Height="100" Fill="Red">
                <Rectangle.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform
                            ScaleX="{Binding Scale}"
                            ScaleY="{Binding Scale}" />
                        <RotateTransform
                            Angle="{Binding Angle}" />
                        <TranslateTransform
                            X="{Binding X}"
                            Y="{Binding Y}" />
                    </TransformGroup>
                </Rectangle.RenderTransform>
            </Rectangle>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

Model:

public class RectangleModel
{
    public double X {get; private set;}
    public double Y {get; private set;}
    public double Scale {get; private set;}
    public double Angle {get; private set;}

    public RectangleModel(double x, double y, double scale, double angle)
    {
        X = x;
        Y = y;
        Scale = scale;
        Angle = angle;
    }
}
1

1 Answers

1
votes

That's because ScaleTransform (and other transforms) inherit from Freezable. Freezables are handled in a special way regarding inheriting data context. When dependency property of dependency object is set to some value, and that value is freezable (and not frozen) - it will inherit data context from "parent" object, even though freezable itself might be not part of tree at all.

In this case, "parent" dependency object is Rectangle (part of tree), target dependency property is RenderTransform and value being set is ScaleTransform. Because it matches criteria above (such as being freezable) - ScaleTransform inherits data context from its "parent" (not in a tree sense) - Rectangle. So all bindings work correctly. Why WPF designer fails to recognize that is another story, there are a lot of things it cannot recognize.

If you inherit your own class from Freezable - it will behave in the same way, which often might be useful.