Changing RenderTransformOrigin property of rotated object - silverlight

how can I make a rotated object stand still when its RenderTransformOrigin property is changed? After running the code below, you can notice by rotating the object (the slider does that), changing the origin of rotation (the button) and rotating it again, that the object slightly moves. What I'm trying to achieve is being able to rotate the object against different points without it moving around whenever I try to switch between them.
<UserControl x:Class="ObjrctRotation.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Canvas x:Name="C" Background="White">
<Path x:Name="thing" RenderTransformOrigin="0,0" Stretch="Fill" Stroke="Black" StrokeThickness="2" Height="93.153" HorizontalAlignment="Left" VerticalAlignment="Top" Width="106.357" UseLayoutRounding="False" Data="M48.723255,124.82815 C41.00029,80.999809 81.000046,65.000069 112.99985,89.000092 C144.99965,113.00011 168.9996,169.00061 136.99989,169.0002 C105.00018,168.99979 104.9999,145.00015 81.000053,145.00015 C57.000206,145.00015 56.44622,168.65649 48.723255,124.82815 z" Canvas.Left="69" Canvas.Top="24" />
<Slider Value="0" Minimum="0" Maximum="360" Width="100" Margin="300,0,0,272" ValueChanged="Slider_ValueChanged" />
<TextBlock x:Name="test" Width="100" Height="20" Canvas.Left="300" Canvas.Top="24" />
<Button Canvas.Left="300" Canvas.Top="24" Content="ChangeCenter" Height="20" Name="button1" Width="100" Click="button1_Click"/>
</Canvas>
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
RotateTransform rotate = new RotateTransform()
{
Angle=e.NewValue
};
thing.RenderTransform = rotate;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
thing.RenderTransformOrigin = new Point(thing.RenderTransformOrigin.X + 0.2, thing.RenderTransformOrigin.Y + 0.2);
}
}

Set the RenderTransformOrigin="0,0" to RenderTransformOrigin="0.5,0.5" so that the transform origin is in the middle of the object you wish to rotate.

Related

UserControl child fill Window

I have a UserControl that is a portion of a wpf window.
<Window>
<Grid>
<!--some other display elements would be here-->
<local:MyUserControl x:Name="Foo" Padding="0,42,0,50"/>
</Grid>
</Window>
Inside MyUserControl I have an element that is a gallery that is normally hidden, but when visible, it should fill the entire screen.
<UserControl>
<Grid>
<!--main display elements would be here-->
<Grid Name="Gallery" Visibility="Hidden">
<Rectangle Fill="Black" Opacity="0.75"/>
<TextBlock Name="GalleryLabel" Foreground="White" TextAlignment="Center">Current Image Title</TextBlock>
<Button Name="CloseGallery" Style="{DynamicResource WhiteTextButton}" Margin="0,0,0,0" Height="25" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Click="GalleryClose_OnClick">X</Button>
<Image Name="GalleryImage" Margin="25"/>
</Grid>
</Grid>
</UserControl>
How can I set the Gallery to fill the entire Window rather than just the UserControl?
I was able to get it to work by adding Margin="0,-42,0,-50" to Gallery, but I don't like that solution. I would rather do something that doesn't involve hard-coding values in the UserControl so that I would be able to have more flexiblility in using it.
Normally it looks like:
where the green Foo area is MyUserControl, and the rest of the things in the window are other elements.
At certain points, I have a gallery display an image, which should fill the entire screen like:
which should fill the entire screen and have a black opaque overlay, along with an image displayed on top of the overlay.
Remove the Padding...
You can use:
<local:MyUserControl x:Name="Foo" VerticalAlignment="Stretch" HorizontalAligment="Stretch"/>
EDIT
I may admit that I still am not sure what you want. But I made something which does the same as you showed in the pictures. But be aware that this as an opinion based question, and the answer is my opinion, there are a lot of ways to achieve this. And this is only one of them:
MainWindow
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myProject="clr-namespace:MyProject"
Title="MainWindow" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Background="Gainsboro" Grid.Row="0">
<StackPanel Orientation="Horizontal">
<Button Content="Show gallery" Width="100" Margin="10"/>
<Button Content="Do something else" Width="150" Margin="10"/>
</StackPanel>
</Border>
<myProject:SomeOtherStuff Grid.Row="1" />
<Border Grid.Row="2" Background="Gainsboro">
<StackPanel Orientation="Horizontal">
<Label Content="Buttom area, can be used for something else"/>
</StackPanel>
</Border>
<myProject:GalleryUserControl x:Name="GalleryUserControl" Grid.Row="0" Grid.RowSpan="3" Visibility="Hidden"/>
</Grid>
SomeOtherStuff UserControl
<UserControl x:Class="MyProject.SomeOtherStuff"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="Green">
<Label VerticalAlignment="Center" HorizontalAlignment="Center" Content="Foo" FontSize="30" FontFamily="Verdana"/>
</Grid>
Gallery UserControl
<UserControl x:Class="XamDataGrid.GalleryUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="500" Width="800">
<Grid Background="#99000000">
<TextBlock Text="Currect image title" Foreground="White" TextAlignment="Center" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<Button Name="CloseGallery" Margin="0,0,0,0" Content="X" Height="25" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Click="GalleryClose_OnClick"/>
<Image Margin="30"/>
</Grid>
An Adorner will be best for you. As it floats above everything else and remains outside the VisualTree too.
UserControl2
<UserControl2 ...>
<Grid>
<Grid Background="#FF709FA6" Opacity="0.3" Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
</Grid>
<Grid Width="600" Height="700">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF37DAEA" Offset="0"/>
<GradientStop Color="#FFE84242" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<!-- Gallery controls -->
<Button Content="Welcome to Gallery" HorizontalAlignment="Left" IsHitTestVisible="True" Margin="112,126,0,0" VerticalAlignment="Top" Height="68" FontSize="48" Click="Button_Click_1"/>
<TextBlock HorizontalAlignment="Left" Margin="83,42,0,0" TextWrapping="Wrap" Text="UserControl2" VerticalAlignment="Top" Foreground="#FF1B0D0D"/>
</Grid>
</Grid>
</UserControl2>
UserControl1
Code :
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// get root Window
DependencyObject current = LogicalTreeHelper.GetParent(this);
while (!(current is Window))
current = LogicalTreeHelper.GetParent(current);
Window root = current as Window;
IEnumerable children = LogicalTreeHelper.GetChildren(root);
Panel p = null;
foreach (var child in children)
{
p = child as Panel; // get first container panel in Window
break;
}
// Create UserControl2 to add to the adorner
UserControl2 ctrlGallery = new UserControl2();
AdornerLayer layer = AdornerLayer.GetAdornerLayer(p);
GalleryAdorner adorner = new GalleryAdorner(p, ctrlGallery);
layer.Add(adorner);
}
}
public class GalleryAdorner : Adorner
{
private Control _child;
VisualCollection collection;
public GalleryAdorner(UIElement elem, Control child)
: base(elem)
{
collection = new VisualCollection(this);
_child = child;
collection.Add(_child);
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Visual GetVisualChild(int index)
{
if (index != 0) throw new ArgumentOutOfRangeException();
return collection[0];
}
protected override Size MeasureOverride(Size constraint)
{
_child.Measure(constraint);
return _child.DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
_child.Arrange(new Rect(new Point(0, 0), finalSize));
return new Size(_child.ActualWidth, _child.ActualHeight);
}
}

OOB Silverlight and content scale on window resize

Good morning,
I faced problem when doing scaleTransform on the content when OOB Silverlight application's window gets resized. The code looks very simple
xaml
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="Aquamarine" RenderTransformOrigin="0,0">
<Rectangle Fill="Aqua" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Height="150">
<TextBlock FontSize="20" Text="Hello World" Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center"/>
<Button Content="Button" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</UserControl>
C#
public MainPage()
{
InitializeComponent();
SizeChanged += MainPage_SizeChanged;
}
void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
ScaleTransform scaleTransform = new ScaleTransform();
scaleTransform.ScaleX = (Application.Current.MainWindow.Width / 500f);
scaleTransform.ScaleY = (Application.Current.MainWindow.Height / 500f);
scaleTransform.CenterX = 0;
scaleTransform.CenterY = 0;
// this.RenderTransform doesn't work either.
LayoutRoot.RenderTransform = scaleTransform;
}
The content gets scaled when the main window is resized, but, for some reason, I see white background of the window when scaling down. It seems that the content is scaled down faster than window and I don't know what I am doing wrong. The code seems logical and should work, shouldn't it?
The LayoutTransformer saved my day. I have changed the code and xaml as follows and everything works now. Code may need a little tweaking though.
xaml
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:layout="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="500">
<layout:LayoutTransformer x:Name="LayoutTransformer">
<layout:LayoutTransformer.Content>
<Grid x:Name="LayoutRoot" Background="AntiqueWhite">
<Rectangle Fill="Aqua" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Grid VerticalAlignment="Center" HorizontalAlignment="Center" Height="150">
<TextBlock FontSize="20" Text="Hello World" Margin="5" VerticalAlignment="Top" HorizontalAlignment="Center"/>
<Button Content="Button" VerticalAlignment="Bottom" HorizontalAlignment="Center"/>
</Grid>
</Grid>
</layout:LayoutTransformer.Content>
<layout:LayoutTransformer.LayoutTransform>
<ScaleTransform x:Name="ContentScale" CenterX="0" CenterY="0" ScaleX="1" ScaleY="1" />
</layout:LayoutTransformer.LayoutTransform>
</layout:LayoutTransformer>
</UserControl>
C#
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
SizeChanged += MainPage_SizeChanged;
}
void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
{
double yScale = ActualHeight / 500f;
double xScale = ActualWidth / 500f;
double value = GetScale(xScale, yScale);
ContentScale.ScaleX = value;
ContentScale.ScaleY = value;
LayoutTransformer.ApplyLayoutTransform();
}
private double GetScale(double xScale, double yScale)
{
return Math.Max(0.1, Math.Min(xScale, yScale));
}
}

Trigger a fade out animation when slider's value changes

I'm trying to bind the Opacity property of a Rectangle shape to the Slider's value. So that when its value passes 2, the Rectangle fades out and when we decrease the slider's value and it passes the value of 2 it appears again with a fade in animation. What's the best practice to do this?
<Window x:Class="Layout.AnimateOpacity"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AnimateOpacity" Height="300" Width="300">
<DockPanel VerticalAlignment="Center" HorizontalAlignment="Center"
Height="300" Width="300">
<Canvas DockPanel.Dock="Top"
Width="300" Height="200"
Background="Black">
<Rectangle x:Name="myRectangle"
Width="100" Height="100"
Canvas.Left="100" Canvas.Top="60"
Fill="Yellow">
</Rectangle>
</Canvas>
<Slider x:Name="mySlider" DockPanel.Dock="Bottom"
Height="30" Width="250"
Value="1" Maximum="3" Minimum="0" />
</DockPanel>
</Window>
Hook ValueChanged event of slider and there you can do animation based on new and old value of slider.
XAML:
<Slider x:Name="mySlider" DockPanel.Dock="Bottom"
Height="30" Width="250"
Value="1" Maximum="3" Minimum="0"
ValueChanged="mySlider_ValueChanged" />
Code behind:
private void mySlider_ValueChanged(object sender,
RoutedPropertyChangedEventArgs<double> e)
{
if (e.NewValue > 2 && e.OldValue <= 2)
{
DoubleAnimation fadeOutAnimation = new DoubleAnimation(0.0,
new Duration(TimeSpan.FromSeconds(1)));
myRectangle.BeginAnimation(Rectangle.OpacityProperty, fadeOutAnimation);
}
else if(e.NewValue < 2 && e.OldValue >= 2)
{
DoubleAnimation fadeInAnimation = new DoubleAnimation(1.0,
new Duration(TimeSpan.FromSeconds(1)));
myRectangle.BeginAnimation(Rectangle.OpacityProperty, fadeInAnimation);
}
}

Animate control with respecting parents/container

I have a control that I move with help of animation from the bottom to the final position. My problem is now that I want to change the behaviour of the animation, so that it respects the outer container (DarkGray).
The orange Ractangle should only be visible on the white background and not on the darkgray Grid!
Code:
MainWindow.xaml:
<Grid Background="DarkGray">
<Grid Margin="50"
Background="White">
<Rectangle x:Name="objectToMove"
VerticalAlignment="Bottom"
Fill="Orange"
Height="50"
Width="50"/>
<Button Height="20"
Width="40"
Margin="20"
Content="Move"
Click="Button_Click"
VerticalAlignment="Top"/>
</Grid>
</Grid>
MainWindow.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
var target = objectToMove;
var heightOfControl = target.ActualHeight;
var trans = new TranslateTransform();
target.RenderTransform = trans;
var myAnimation = new DoubleAnimation(heightOfControl, 0, TimeSpan.FromMilliseconds(600));
trans.BeginAnimation(TranslateTransform.YProperty, myAnimation);
}
Current:
Desired solution:
Use ClipToBounds Property for this.
<Grid Margin="50"
Background="White"
ClipToBounds="True">

BarChart Values not updating

I am trying to develop a application where-in I a want to generate a random number after every three seconds, insert that number into a listBox and using DataTemplate display the ListBox as a rectangle.
This is for reference.
Now the problem is that I have used a DispatcherTimer which 'ticks' after 3 seconds but the rectangle is not updated.
I am posting my XAML and .cs code. Any hints ?
namespace ListBarGraph
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer dt = new DispatcherTimer();
DataFactory df = new DataFactory();
public MainWindow()
{
InitializeComponent();
dt.Tick += new EventHandler(dt_Tick);
dt.Interval = new TimeSpan(0, 0, 3);
dt.Start();
this.PreviewKeyDown += new KeyEventHandler(MainWindow_PreviewKeyDown);
}
void dt_Tick(object sender, EventArgs e)
{
df.GetData();
}
}
public class DataFactory
{
int number = 0;
public IEnumerable<int> GetData()
{
Random random = new Random();
number = random.Next(0, 100);
return new int[] { 0, number };
}
}
}
<Window x:Class="ListBarGraph.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ListBarGraph"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="someData" ObjectType="{x:Type local:DataFactory}" MethodName="GetData" />
<DataTemplate x:Key="BarChartItemsTemplate">
<Border Width="300" Height="50">
<Grid>
<Rectangle Fill="Red" StrokeThickness="2" Height="40" Width="{Binding}" HorizontalAlignment="Right" VerticalAlignment="Bottom">
<Rectangle.LayoutTransform>
<ScaleTransform ScaleX="1.5"/>
</Rectangle.LayoutTransform>
</Rectangle>
</Grid>
</Border>
</DataTemplate>
<ItemsPanelTemplate x:Key="BarChartItemsPanel">
<VirtualizingStackPanel IsItemsHost="True">
<VirtualizingStackPanel.LayoutTransform>
<TransformGroup>
<RotateTransform Angle="90"/>
<ScaleTransform ScaleX="-1" ScaleY="1"/>
</TransformGroup>
</VirtualizingStackPanel.LayoutTransform>
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Source={StaticResource someData}}" ItemTemplate="{DynamicResource BarChartItemsTemplate}" ItemsPanel="{DynamicResource BarChartItemsPanel}"/>
</Grid>
</Window>
Your XAML is bound to one instance of DataFactory as created by the ObjectProvider, whilst your code-behind creates another instance altogether, to which the UI is not bound.
Try this to get you started. In your XAML, remove the ObjectProvider and change your ListBox to:
<ListBox ItemsSource="{Binding}" ...
Inside dt_Tick, do this:
this.DataContext = df.GetData();

Resources