ScaleTransform no effect when in DataTemplate - c#

I am using ScaleTransform to change the size of a UserControl on a Canvas. It works perfectly until I use the ItemsControl Control.
The problem is that I need the scaling to be centered, the UserControl should not "move". As soon as it is inside the ItemsControl, the item Scales on Position x=0, y=0 instead of the center.
Would be great to know what I am doing wrong!
Here is some XAML showing it does not work (there is a single item in DataSource, nothing special it only displays a red rectangle on the window).
// This slider is used to scale the Grid inside the ItemsControl.
<Slider x:Name="pointResizeSlider" Margin="10,10,10,0" VerticalAlignment="Top" Maximum="7" Value="1"/>
// The items Control.
<ItemsControl Name="icTest" Background="Blue" Width="200" Height="200">
<ItemsControl.ItemTemplate>
<DataTemplate>
// For simplicity I am using a simple 100x100 Grid. This will get scaled.
<Grid Margin="0 0 5 5" Width="100" Height="100" Background="Red">
<Grid.LayoutTransform>
<TransformGroup>
<ScaleTransform
// This would make it pretty obvious, if it would work.
// Shows no effect.
CenterX="1000"
CenterY="1000"
ScaleX="{Binding Path=Value, ElementName=pointResizeSlider}"
ScaleY="{Binding Path=Value, ElementName=pointResizeSlider}" />
</TransformGroup>
</Grid.LayoutTransform>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Edit
Using RenderTransform works in this case, but I have to calculate the ActualSize of the UserControl (which does not work right now with RenderTransform). Why does LayoutTransform not work in this case?

Related

scrollviewer zoom only one element

I have to zoom an image in uwp application, which works fine, but the design requires to have another image (that works as a button) in front of it and I dont want that element to be zoomed as well. It has to be only the image inside the canvas tag, this is how I have it now.
<ScrollViewer MinZoomFactor="1"
ZoomMode="Enabled"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<RelativePanel HorizontalAlignment = "Stretch" >
<Canvas x:Name="canvas">
<Image Source = "{Binding Test,UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Canvas >
<Button RelativePanel.AlignTopWithPanel="True"
Height="55"
Command="{Binding Path=CollapseSplitView}"
CommandParameter="{Binding ElementName=SplitV}">
<Button.Background>
<ImageBrush ImageSource = "/Assets/btlist.png" ></ ImageBrush >
</Button.Background >
</Button >
<Image RelativePanel.AlignBottomWithPanel="True"
RelativePanel.AlignRightWithPanel="True"
Source="/Assets/escala-x.png"
Width="130"
Height="70"
Margin="0,0,20,0"
ScrollViewer.IsZoomChainingEnabled="False"
ScrollViewer.IsZoomInertiaEnabled="False">
</Image>
</RelativePanel>
</ScrollViewer>
thats the xaml I have and which makes the zoom work for all elements inside of it. I tried to set scrollViewer.zoomMode=disabled for the elements that are not in the canvas but without luck. Any ideas? Thanks!
I finally fixed it by adding a scrollViewer inside the RelativePanel and then wrap the contents I wanted to zoom inside a StackPanel and then a Grid to be able to have multiple elements inside. Thanks all

WPF How to make a Viewbox aware of its available space from within a StackPanel

I have a custom WPF control based on Soroosh Davaee’s ImageButton example at http://www.codeproject.com/Tips/773386/WPF-ImageButton. The custom control combines an Image and TextBlock in a horizontal StackPanel within a Button. (BTW, to get Soroosh’s example to run, I had to edit the solution properties so that “SampleView” is the startup project rather than “ExtendedButton” being the startup project.)
I want the text in the TextBlock to automatically shrink if necessary to avoid clipping at the right edge if the text is too long to fit naturally in the button. For example, if I edit Soroosh's MainWindow.xaml to make the button text too long to fit...
...
<EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
...
<EB:ImageButton Width="100" Height="30" Content="TextTooLongToFitInTheButton" Grid.Row="2"
...
...the result is the following buttons with clipped text:
In researching this, it seems the simplest way to auto-shrink the content of a TextBlock is to wrap it within a Viewbox:
<Viewbox StretchDirection="DownOnly" Stretch="Fill">
<TextBlock ... />
</Viewbox>
DownOnly apparently prevents the Viewbox from enlarging the text to fill the space, and Fill (as opposed to Uniform) seems to tell it to stretch (shrink) only the dimension that needs to shrink (i.e. the horizontal dimension in my case).
In Soroosh's example Generic.xaml file, I wrapped the TextBlock in such a Viewbox:
<Button >
<StackPanel Orientation="Horizontal">
<Image Margin="2 0"
Source="{TemplateBinding Image}"
Width="{TemplateBinding ImageWidth}"
Height="{TemplateBinding ImageHeight}"
Visibility="{TemplateBinding Image,Converter={StaticResource VisibilityConvertor}}"
VerticalAlignment="Center"/>
I added--> <Viewbox StretchDirection="DownOnly" Stretch="Fill">
<TextBlock Text="{TemplateBinding Content}"
VerticalAlignment="Center"/>
I added--> </Viewbox>
</StackPanel>
</Button>
This produced exactly the same clipped button text. Just experimenting, I tried forcing the Viewbox to have a fixed width...
<Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">
...which produced this:
...which shows the capability of the Viewbox, if only it could somehow know its available width when it's inside the StackPanel.
I did note that if I wrap the Viewbox around the whole StackPanel, it successfully auto-shrinks the entire content of the StackPanel:
<Button >
<Viewbox StretchDirection="DownOnly" Stretch="Fill" Width="60">
<StackPanel Orientation="Horizontal">
<Image Margin="2 0"
Source="{TemplateBinding Image}"
Width="{TemplateBinding ImageWidth}"
Height="{TemplateBinding ImageHeight}"
Visibility="{TemplateBinding Image,Converter={StaticResource VisibilityConvertor}}"
VerticalAlignment="Center"/>
<TextBlock Text="{TemplateBinding Content}"
VerticalAlignment="Center"/>
</StackPanel>
</Viewbox>
</Button>
...which produces very nearly what I want:
...but both the image and text are shrunk, and I want only the text shrunk.
How can I make the Viewbox, wrapping only the TextBox, know its available width (and height, I suppose) from within a cell of the StackPanel?
This is a common problem. The solution is simply to not use a StackPanel to do any kind of layout that requires re-sizing of child controls. It's simply not the correct Panel for the job. Instead, try using a Grid panel, which will resize its child controls. The StackPanel control is really only good for the most basic of layout duties... try anything more adventurous and you'll find yourself getting these issues.
One other alternative is to use the TextBlock.TextTrimming Property to trim the text instead... you could put the full text into a ToolTip too.

How can I layer a Polygon over a StackPanel, which is inside a ScrollViewer?

I have a horizontal ScrollViewer that contains a single StackPanel, which is initially empty. UserControls are created on button-click, and added to the StackPanel. The code looks something like this:
<ScrollViewer Grid.Column="1" Grid.Row="0" RequestedTheme="Dark" ScrollViewer.HorizontalScrollMode="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<StackPanel x:Name="Container" HorizontalAlignment="Left" VerticalAlignment="Top" Width="Auto">
<!--User controls added here dynamically-->
</StackPanel>
</ScrollViewer>
As you can see the ScrollViewer is itself in a larger Grid. Now I would like a Polygon to be added to this ScrollViewer, but I cannot add it as a child directly, since "Content can only be set once". If I add it to the StackPanel in code-behind (after setting Canvas left, top and ZIndex), the UserControls are added below the Polygon. I want them to be under or over, either will do. Is this even possible? Right now, my Polygon shares the same Grid Row and Column as the ScrollViewer. Here is my Polygon:
<Polygon x:Name="Gripper" Grid.Column="1" Grid.Row="0" Points="0,0 0,730 -30,750 -30,800 30,800 30,750 0,730 0,100" Stroke="#DEDEDE" StrokeThickness="1" Opacity="1.0" ManipulationMode="TranslateX" ManipulationDelta="Gripper_ManipulationDelta">
<Polygon.Fill>
<SolidColorBrush Color="#FFFFFF" Opacity="0.9"/>
</Polygon.Fill>
<Polygon.RenderTransform>
<CompositeTransform />
</Polygon.RenderTransform>
</Polygon>
I am okay with adding it in XAML or C#, but I think I would prefer to do it in C# since I would like to change the points based on the size of the screen.
Put another container control between the StackPanel and the Polygon. An intermediate Grid will let you control their placement by row and column as normal. An intermediate StackPanel will let the Container stack and Polygon stack separately from the items within the Container stack:
<ScrollViewer>
<Grid>
<StackPanel x:Name="Container" HorizontalAlignment="Left" VerticalAlignment="Top" Width="Auto">
<!--User controls added here dynamically-->
</StackPanel>
<Polygon />
</Grid>
</ScrollViewer>

Scalling the items in items Control

I am developing a control (Items control) to show boxes in a Room(for example sack).
If the room size is 10 *10 feet then I have to scale it to fit my Screen.
Also all the objects in the room will also need to be scaled.
In my view model I have a collection of these objects(i.e. boxes) with actual dimension.
The ItemPanel of my items control is like a canvas where I can freely move the objects.
currently in my Measure Override or Arrange override of the itemsPanel I get the height and width of the panel. With that height and width I apply the scaling to object while arranging.
So my question is, is the approach better or there is a better alternative.
Regards
Saurabh Dighade
Take a look at this code
<Grid x:Uid="Grid_1" Margin="10" ToolTip="{Binding ToolTip}">
<StackPanel x:Uid="StackPanel_1" Grid.Row="1" Orientation="Horizontal">
<Slider x:Uid="ScaleSlider" x:Name="ScaleSlider" Minimum="0.2" Maximum="5" LargeChange="0.05" SmallChange="0.01"
Value="{Binding ScaleSlider}" IsSnapToTickEnabled="True" TickFrequency="0.1" Visibility="Hidden"/>
</StackPanel>
<ScrollViewer x:Uid="ScrollViewer_1" Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Border x:Uid="AlStatusBorder" BorderBrush="#101010" BorderThickness="3"
Background="{Binding Color}"
x:Name="AlStatusBorder"
Padding="5"
CornerRadius="10" HorizontalAlignment="Center" VerticalAlignment="Top">
<Grid x:Uid="Grid_2">
<!-- Tachometer Gauge -->
<gauge:CircularGauge x:Uid="gauge:CircularGauge_1" Grid.Row="1" Grid.Column="2" FrameType="CircularTopGradient" Width="150" Height="150" Radius="75" Background="#444444"
RimBrush="#444444">
<gauge:CircularGauge.LayoutTransform >
<ScaleTransform x:Uid="ScaleTransform_1" ScaleX="{Binding ElementName=ScaleSlider, Path=Value}"
ScaleY="{Binding ElementName=ScaleSlider, Path=Value}"/>
</gauge:CircularGauge.LayoutTransform>
</gauge:CircularGauge>
</Grid>
</Border>
</ScrollViewer>
</Grid>
In grid_2 I implement my userControl. When I change a property ScaleSlider, element becomes bigger or smaller, and my usercontrol that is inside also changes it's sizes. May be it is what you are looking for. At least I can move this userControl; change sizes only by changing one property. Note that Im binding ScaleX and ScaleY values

Transforms on WriteableBitmap

I'm writing app in WP7 mango and try to transform image loaded from binded to WriteableBitmap in XAML for example like this:
<Grid>
<ScrollViewer>
<Image Source="{Binding SourceImage}">
<Image.RenderTransform>
<RotateTransform Angle="{Binding RotateAngle}"/>
</Image.RenderTransform>
</Image>
</ScrollViewer>
</Grid>
I bind Angle with my property Angle in my ViewModel, i change from slider this value but image doesn't rotate. Raising property changed is working correct.
When i do it with image loaded from contets file, static image, it works.
Really weird. I have yet to understand where the problem comes from, but you can get around using Projection instead of RenderTransform:
<Grid>
<ScrollViewer>
<Image Source="{Binding SourceImage}">
<Image.Projection>
<PlaneProjection RotationZ="{Binding RotateAngle}" />
</Image.Projection>
</Image>
</ScrollViewer>
</Grid>
Edit:
Ok, actually it seems the problem comes from the ScrollViewer rather than the Image. Set the RotateTransform directly on the ScrollViewer and it should work:
<Grid>
<ScrollViewer>
<ScrollViewer.RenderTransform>
<RotateTransform Angle="{Binding RotateAngle}" />
</ScrollViewer.RenderTransform>
<Image Source="{Binding SourceImage}" />
</ScrollViewer>
</Grid>
Or put the Image inside a Grid inside the ScrollPanel:
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Image Source="{Binding SourceImage}">
<Image.RenderTransform>
<RotateTransform Angle="{Binding RotateAngle}" />
</Image.RenderTransform>
</Image>
</Grid>
</ScrollViewer>
But I'm still clueless about why this happens.
Edit 2:
Ok I found the bug. It has been introduced in the last WP7 builds. Basically, the scrollviewer will overwrite the RenderTransform of its child if it's different than its own.
So you have three solutions:
Define the RenderTransform directly on the ScrollViewer
Wrap your child element in a dummy container element. This way, the dummy element's rendertransform get overwrited and not yours:
At initialization, replace the ScrollViewer's RotateTransform with the element's:
public MainPage()
{
this.InitializeComponent();
this.ScrollViewer.RenderTransform = this.Image.RenderTransform;
}
I would personnaly go with the first or second solution. I fear there could be unexpected side effects with the third solution.

Categories