Reputation: 27515
I have an application where I am adding various instances to a Canvas dynamically and the underlying Canvas has a scaling LayoutTransform. This works great for visuals like rectangles, where they correctly maintain a fixed stroke width, but expand in shape width/height as the canvas is 'zoomed' with the LayoutTransform. For TextBlock instances, however, the layout transformation is actually scaling the rendering of the text, making the font effectively larger. What I'd like to have happen instead is for the upper left origin of the TextBlock to translate with the layout transformation, with the text remaining the same size.
Here is the XAML for the ItemsControl that creates the Canvas:
<ItemsControl ItemsSource="{Binding Annotations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding StartX}"/>
<Setter Property="Canvas.Top" Value="{Binding StartY}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.LayoutTransform>
<TransformGroup>
<ScaleTransform ScaleX="{Binding ZoomScale}" ScaleY="{Binding ZoomScale}"
CenterX="0.5" CenterY="0.5"/>
</TransformGroup>
</ItemsControl.LayoutTransform>
</ItemsControl>
Here are some of the data templates that render the Annotations from the bound collection:
<DataTemplate DataType="{x:Type Annotations:RectangleAnnotation}">
<Rectangle Width="{Binding Width}" Height="{Binding Height}" Stroke="Blue" IsHitTestVisible="False"/>
</DataTemplate>
<DataTemplate DataType="{x:Type Annotations:TextAnnotation}">
<TextBlock Text="{Binding Text}" Foreground="Orange" IsHitTestVisible="False"/>
</DataTemplate>
The Annotation instances themselves are simple INotifyPropertyChanged implementations with the relevant bound properties (StartX, StartY and Text for the TextAnnotation.)
I haven't been able to find any easy way to prevent the layout scaling of the text. However, before I start hacking my way to a solution, I thought I'd check: does anybody know of a clean way to fix this?
Upvotes: 1
Views: 922
Reputation: 27515
I couldn't bind to the Inverse, as @hbarck suggested, as this was a GeneralTransform rather than a Transform. I got around the issue by binding to the ScaleTransform by element name and using a value converter to invert the scaling:
<Controls:InvertConverter x:Key="Invert"/>
<DataTemplate DataType="{x:Type Annotations:TextAnnotation}">
<TextBlock Text="{Binding Text}" Foreground="Orange" IsHitTestVisible="False">
<TextBlock.RenderTransform>
<ScaleTransform ScaleX="{Binding ScaleX, ElementName=AnnotationScale, Converter={StaticResource Invert}}"
ScaleY="{Binding ScaleY, ElementName=AnnotationScale, Converter={StaticResource Invert}}"/>
</TextBlock.RenderTransform>
</TextBlock>
</DataTemplate>
And the converter code below:
public sealed class InvertConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value.GetType() != typeof(double) || targetType != typeof(double))
return null;
return 1/(double)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || value.GetType() != typeof(double) || targetType != typeof(double))
return null;
return 1 / (double)value;
}
}
Upvotes: 1
Reputation: 2944
Every Transform has an Inverse property which undoes its effect. So, you can bind the TextBlock's RenderTransform to the Inverse of the Transform which scales the Canvas, that should undo its effect on the text rendering.
The upper left corner normally is the origin for scaling, so if all is default, the Text should move to the upper left corner as you specified. However, if you're using combined transforms or a different zoom center on the canvas, you might have to play around with the parameters a bit, but it should be quite easy to e.g. write a converter which only takes the scale factors of a transform in order to create an inverse scale transform without shifting the zoom center.
Upvotes: 2