.NET Framework Bookmark and Share   
 index > Windows Presentation Foundation (WPF) > LayoutTransform and ScaleTransform; CenterX/CenterY not working
 

LayoutTransform and ScaleTransform; CenterX/CenterY not working

I have an image I am scaling with a ViewBox, setting LayoutTransform to a ScaleTransform. My XAML looks like this:

<ScrollViewer

x:Name="m_SiteImageScroller"

x:FieldModifier="private"

Grid.Column="0"

HorizontalScrollBarVisibility="Auto"

VerticalScrollBarVisibility="Auto">

<Viewboxx:Name="m_SiteImageViewbox"x:FieldModifier="private">

<Viewbox.LayoutTransform>

<ScaleTransformx:Name="m_Scale"x:FieldModifier="private"/>

</Viewbox.LayoutTransform>

<InkCanvasx:Name="m_DrawingLayer"EditingMode="None">

<Imagex:Name="m_Image"x:FieldModifier="private"Source="Raw.jpg">

</Image>

</InkCanvas>

</Viewbox>

</ScrollViewer>


I then have some C# code which reads a Slider and assigns to ScaleTransform.ScaleX/ScaleY:

privatevoidm_ScaleAdjuster_ValueChanged(objectsender,RoutedPropertyChangedEventArgs<double>e)
{
m_Scale.ScaleX=m_ScaleAdjuster.Value;
m_Scale.ScaleY=m_ScaleAdjuster.Value;
}

Problem is, I can assign any values to the ScaleTransform's CenterX and CenterY properties (to scale from the middle rather than (0,0) ) and they haveno effectwhatsoever. NONE. I tried using the transform as a RenderTransform instead of a LayoutTransform and setting RenderTransformOrigin to (.5,.5). This works. The image scales from the center (but of course then I have the problems of doingthe scalingbehind the layout system's back). But I can't for the life of me get the LayoutTransform to work with the CenterX / CenterY properties.

Any ideas?

TIA,
John
John_C

Hi,

in fact your problem is not with the viewbox, it is with the ScrollViewer. What happens is that the size of the ViewBox changes, and that the ScrollViewer displays a bigger background, but the value of the scrollbars doesn't change. What you need is some logic to remember the relative setting of the scrollbars every time the userchanges the scrollbars, and to change the value of the scrollbars to the same relative position if the size of the ViewBox changes.

This does the job of keeping the same point in the middle of ScrollViewer's viewport when you are changing the scale factor:


Private _RelScrollX As Double

Private _RelScrollY As Double

PrivateSubScroller_ScrollChanged(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Controls.ScrollChangedEventArgs)
Ife.ExtentHeightChange<>0Ore.ExtentWidthChange<>0Then
DimscrollAsScrollViewer=DirectCast(sender,ScrollViewer)
scroll.ScrollToHorizontalOffset(Math.Max(_RelScrollX*e.ExtentWidth-0.5*e.ViewportWidth,0))
scroll.ScrollToVerticalOffset(Math.Max(_RelScrollY*e.ExtentHeight-0.5*e.ViewportHeight,0))
Else
Ife.ExtentWidth>0Then
_RelScrollX=(e.HorizontalOffset+0.5*e.ViewportWidth)/e.ExtentWidth
EndIf
Ife.ExtentHeight>0Then
_RelScrollY=(e.VerticalOffset+0.5*e.ViewportHeight)/e.ExtentHeight
EndIf
EndIf
EndSub

and you need to add this to your ScrollViewer element:

ScrollChanged="Scroller_ScrollChanged"


  • Marked As Answer byJohn_C Saturday, January 17, 2009 11:16 PM
  • Edited byhbarck Saturday, January 17, 2009 5:11 PMadded code
  •  
hbarck
Those coordinates are supposed to be in pixels. You're specifying 0.5 presumably because you want the center; you actually need to specify whatever is half the width of the object.
Controls for WPF, Windows Forms and Silverlight at http://www.divelements.co.uk
Tim Dawson

ScaleTransform.CenterX/CenterY are in pixels. RenderTransformOrigin.CenterX / CenterY is a proportion.

I've assigned all kinds of things to ScaleTransform.CenterX/Y:I've tried (Width * .5, Height * .5); (.5, .5); (Int32.MaxValue, Int32.MaxValue) (yes, I actually did this!). No effect.

John_C
*desperation bump*
John_C
This won't work because you're using a layout transform. Layout transforms only affect size, not position. If you set a TranslateTransform as a LayoutTransform, it is ignored, because the layout pass itself determines where to position your content. I believe the same thing applies here - CenterX and CenterY have no meaning during layout since the position has yet to be determined, so only ScaleX and ScaleY, which affect the size of your content, are respected. If you want to move your content relative to its position (as determined by layout) you need to set a render transform on it instead.

To accomplish what I believe you want, where layout respects the scale size increase and you scale from a center point, you could derive your own Viewbox, override its MeasureOverride and scale its size up there for the layout bounds. Then set your ScaleTransform as the RenderTransform.
Brendan Clark - MSFT

Thanks for the help Brendan. It's surprising something like this is so frustrating in WPF. Anyway, ....

I'm still not totally clear how I would calculate the size of my Viewbox subclass.

John_C

Hi,

in fact your problem is not with the viewbox, it is with the ScrollViewer. What happens is that the size of the ViewBox changes, and that the ScrollViewer displays a bigger background, but the value of the scrollbars doesn't change. What you need is some logic to remember the relative setting of the scrollbars every time the userchanges the scrollbars, and to change the value of the scrollbars to the same relative position if the size of the ViewBox changes.

This does the job of keeping the same point in the middle of ScrollViewer's viewport when you are changing the scale factor:


Private _RelScrollX As Double

Private _RelScrollY As Double

PrivateSubScroller_ScrollChanged(ByValsenderAsSystem.Object,ByValeAsSystem.Windows.Controls.ScrollChangedEventArgs)
Ife.ExtentHeightChange<>0Ore.ExtentWidthChange<>0Then
DimscrollAsScrollViewer=DirectCast(sender,ScrollViewer)
scroll.ScrollToHorizontalOffset(Math.Max(_RelScrollX*e.ExtentWidth-0.5*e.ViewportWidth,0))
scroll.ScrollToVerticalOffset(Math.Max(_RelScrollY*e.ExtentHeight-0.5*e.ViewportHeight,0))
Else
Ife.ExtentWidth>0Then
_RelScrollX=(e.HorizontalOffset+0.5*e.ViewportWidth)/e.ExtentWidth
EndIf
Ife.ExtentHeight>0Then
_RelScrollY=(e.VerticalOffset+0.5*e.ViewportHeight)/e.ExtentHeight
EndIf
EndIf
EndSub

and you need to add this to your ScrollViewer element:

ScrollChanged="Scroller_ScrollChanged"


  • Marked As Answer byJohn_C Saturday, January 17, 2009 11:16 PM
  • Edited byhbarck Saturday, January 17, 2009 5:11 PMadded code
  •  
hbarck

Works like a charm (but then you already knew that 8-] ).

Thanks hbarck! Owe you one...

John

John_C

You can use google to search for other answers

Custom Search

More Threads

• ListBox Items and keyboard events
• NotifyCollectionChanged
• Listview Sorting by multiple columns?
• Tier 2 -- Not necessarily the best indicator of WPF 3D Performance
• Stretching a horizontal listbox
• Licensing WPF styles and templates
• DATA BINDING: Why are ValidationRule and ValueConverter objects always invoked with null value?
• Default Number of Threads
• Grid Stretch
• Listview to Treeview drag drop find drop treeviewitem