I am trying to make a slide in & out animation with c# & WPF.
So far I have managed to code the next lines:
XAML:
<Grid Name="grid" Grid.Column="0" Grid.Row="1">
<Border Name="border" Background="Red"></Border>
</Grid>
c#:
private void Button_Click(object sender, RoutedEventArgs e) {
border.Height = grid.ActualHeight;
if (!isOpen) {
isOpen = true;
DoubleAnimation db = new DoubleAnimation();
db.From = 0;
db.To = grid.ActualHeight;
db.Duration = TimeSpan.FromSeconds(0.5);
border.BeginAnimation(Grid.HeightProperty, db);
} else {
isOpen = false;
DoubleAnimation db = new DoubleAnimation();
db.From = grid.ActualHeight;
db.To = 0;
db.Duration = TimeSpan.FromSeconds(0.5);
border.BeginAnimation(Grid.HeightProperty, db);
}
}
The good thing is that the animation is executed. The bad thing is that this animation has the wrong effect, i mean the animation goes from top to middle and bottom to middle (like if it was shrinking)...
How can i make (or modify in my actual code) the slide effect(top to bottom & bottom to top)?
It has to be in c# code.
You are trying to translate your UI control so use a TranslateTransform (Canvas.Top is possible if you are on a canvas, but inefficient).
Modify your XAML to include a render transform set to a TranslateTransform object:
<Grid Name="grid" Grid.Column="0" Grid.Row="1" ClipToBounds="true">
<Border Name="border" Background="Red">
<Border.RenderTransform>
<TranslateTransform x:Name="borderTransform"/>
</Border.RenderTransform>
</Border>
</Grid>
And animate the Y property of the transform:
DoubleAnimation db = new DoubleAnimation();
db.From = 0;
db.To = grid.ActualHeight;
db.Duration = TimeSpan.FromSeconds(0.5);
borderTransform.BeginAnimation(TranslateTransform.YProperty, db);
Just so you know, doing this is a whole lot cleaner using a Storyboard object (plus you can set it up in XAML!)
Related
I'm using the code below to draw text over a rectangle in a WPF canvas but it seems to stretch/squash the text and sometimes the back colour does not fill the entire box.
I'm looking for a way to make sure the box is always filled and the text is clear. Probably some form of dynamic font sizing?
Thanks.
Rectangle elip = new Rectangle();
elip.Height = 6;
elip.Width = 6;
Brush brush = new SolidColorBrush(Color.FromRgb(n.Value.R,
n.Value.G, n.Value.B));
Label TB = new Label();
TB.HorizontalAlignment = HorizontalAlignment.Stretch;
TB.Margin = new Thickness(0, 0, 0, 0);
TB.Background = brush;
TB.FontSize = 12;
TB.HorizontalContentAlignment = HorizontalAlignment.Center;
TB.Content = n.Value.Stations[0].TrackId;
BitmapCacheBrush bcb = new BitmapCacheBrush(TB);
elip.Fill = bcb;
elip.Stroke = Brushes.Black;
elip.StrokeThickness = 0.5;
elip.MouseDown += ElipOnMouseDown;
Canvas.SetTop(elip, n.Value.Y - elip.Width / 2);
Canvas.SetLeft(elip, n.Value.X - elip.Height / 2);
cMain.Children.Add(elip);
You can stretch the text using a viewbox.
I recommend using a usercontrol to encapsulate all your markup for things like this. You would have to have many thousands of these things before the overhead of a usercontrol vs building rectangles and whatnot would be significant.
I built this usercontrol:
Height="18" Width="24">
<Border BorderBrush="Black"
BorderThickness="1"
Background="Magenta"
>
<Viewbox Stretch="Uniform">
<TextBlock Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=UserControl}}"
TextAlignment="Center"
Margin="2"
/>
</Viewbox>
</Border>
</UserControl>
Might not be precisely what you want in terms of width, height or whatever.
You could instantiate one of these, set it's Tag, canvas top and left and add it to the canvas.
Here's the equivalent markup I used to prove it:
Title="MainWindow" >
<Grid>
<Canvas>
<local:StationView Canvas.Left="20"
Canvas.Top="100"
Tag="16B"/>
</Canvas>
</Grid>
</Window>
I am working on a WPF project, trying to create an analog clock. I have an image of a clock (without the hands) and have set it as a background. I also have images of two hands of clock, which I want to rotate keeping one end fixed (like it happens in a clock). How can I rotate the image keeping its one end fixed in C#.NET (WPF)? What I have tried is the following code:
namespace AnalogWatch
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer dispatcherTimer;
private int degrees = 0;
public MainWindow()
{
InitializeComponent();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
degrees += 5;
if (degrees > 360)
{
degrees = 0;
}
RotateTransform transform = new RotateTransform(degrees,StickImg.Width/2,StickImg.Height/2);
//StickImg.RenderTransformOrigin = new System.Windows.Point(0, 0);
StickImg.RenderTransform = transform;
}
private void Window_ContentRendered_1(object sender, EventArgs e)
{
dispatcherTimer.Start();
}
}
}
It is rotating the image but not keeping its one end fixed. What is the problem here ?
XAML is:
<Window x:Class="AnalogWatch.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" ContentRendered="Window_ContentRendered_1">
<Grid>
<Image x:Name="StickImg" HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Margin="207,70,0,0" Source="stick.png"/>
</Grid>
</Window>
Updated.
Your code should work if clock hand exactly in the center of rectangular image.
Like this one
You can do either like you did
RotateTransform transform =new RotateTransform(degrees, StickImg.Width/2,StickImg.Height/2);
or
RotateTransform transform = new RotateTransform(degrees);
StickImg.RenderTransformOrigin = new Point(0.5, 0.5);
Use the RenderTransformOrigin of the element to set the center of rotation.
Note that the coordinates are scaled to 0..1
So to rotate around the center:
RenderTransformOrigin="0.5, 0.5"
Just make sure that the pivot of the hand is in the center of the element.
here's the code i'm using and it works like charm..as qwr suggested clock hand should be exactly in the center of rectangular image
c# code
DispatcherTimer clock = new DispatcherTimer();
public AnalogClock()
{
InitializeComponent();
clock.Interval =TimeSpan.FromMilliseconds(100);
clock.Tick += clock_Tick;
clock.Start();
}
void clock_Tick(object sender, EventArgs e)
{
double milsec = DateTime.Now.Millisecond;
double sec = DateTime.Now.Second;
double min = DateTime.Now.Minute;
double hr = DateTime.Now.Hour;
seconds.LayoutTransform = new RotateTransform(((sec / 60) * 360)+((milsec/1000)*6));
minutes.LayoutTransform = new RotateTransform((min * 360 / 60)+((sec/60)*6));
hours.LayoutTransform = new RotateTransform((hr * 360 / 12)+(min/2));
}
and the XAML code for images
<Grid Margin="-100">
<Image x:Name="clockface" RenderOptions.BitmapScalingMode="HighQuality" Source="images/panel.PNG" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="hours" RenderOptions.BitmapScalingMode="HighQuality" Source="images/hours.PNG" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="minutes" RenderOptions.BitmapScalingMode="HighQuality" Source="images/minutes.PNG" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" HorizontalAlignment="Center" Height="194" Margin="100" Width="194"/>
<Image x:Name="seconds" RenderOptions.BitmapScalingMode="HighQuality" Source="images/seconds.PNG" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="194" Margin="100" Width="194"/>
</Grid>
note the i've used the code in a separate usercontrol..
just make sure that the margin between the clock hand image and the grid i'ts contained in should be enough to make room for the image to rotate else it will displace while rotating..
hope this helps..!
So my question is pretty simple:
I have a StackPanel with two objects: a button and an rectangle (which is filled with an image by clicking the button). Now, an additional thing that has to happen is when the button is clicked, the entire stackpanel has to be flipped upside down AND it has to stay in the same place.
I have tried with the RenderTransformOrigin-property set on "0.5,0.5"
but I haven't got any luck with this .. either the stackpanel moved to another location or it disappeared (out of bounds)
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Name="pnlFlip" RenderTransformOrigin="0.5,0.5">
<Button Content="Test" Margin="200,78,197,-78" Name="btnTest" Click="btnTest_Click" Height="30"/>
<Rectangle Margin="175,146,162,-239" Name="rectTest" Fill="Red" Height="127"/>
</StackPanel>
</Grid>
</Window>
The code for my buttons is like this:
private int scale = 1;
private int angle = 180;
private void btnTest_Click(object sender, RoutedEventArgs e)
{
ImageBrush img = new ImageBrush();
img.ImageSource = new BitmapImage(new Uri("pack://application:,,,/WpfApplication1;component/Resources/Images/logo.jpg"));
rectTest.Fill = img;
//Trying a ScaleTranfsformObject
ScaleTransform st = new ScaleTransform();
if(scale == 1)
{
scale = -1;
st.ScaleY = scale;
}
else
{
scale = 1;
st.ScaleY = scale;
}
//Trying a RotateTransform Object
RotateTransform rt = new RotateTransform();
if(angle == 180)
{
rt.Angle = angle;
angle += 180;
}
else
{
rt.Angle = angle;
angle -= 180;
}
pnlFlip.RenderTransform = rt;
}
So what am I doing wrong/how do I fix this?
Using storyboard is better approach than setting this directly in code in click handler. You will get smooth changes in UI.
Following will achieve your objective with XAML only, without any code behind. Setting RenderTransformOrigin in the StackPanel is what keeps it in the center after running the rotate transform.
To activate the animation on click, we just add a Button.Trigger handler which has storyboard on DoubleAnimation to change the angle to 180 degree in the StackPanel. Rest of the XAML is what you had before.
<StackPanel x:Name="pnlFlip" RenderTransformOrigin="0.5,0.5">
<StackPanel.RenderTransform>
<RotateTransform />
</StackPanel.RenderTransform>
<Button Content="Test" Margin="200,78,197,-78" Name="btnTest" Height="30">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation To="180" Storyboard.TargetName="pnlFlip" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
<Rectangle Margin="175,146,162,-239" Name="rectTest" Fill="Red" Height="127"/>
</StackPanel>
This works fine on my computer (minus the code for the image in your Resources.)
Here's how it looks when the application launches:
And here's how it looks after I click the button:
Which part of this falls short of your intentions?
Note that you can use a ternary operator to remove your conditional branches and cut down on code, like so:
angle = angle == 180 ? 0 : 180;
rt.Angle = angle;
I want to create a wheel control for my school project using Visual studios 2012.
What I have right now is the image and it is able to rotate when I click a button and stop at random positions.
However, I am not sure how to detect the position when the image stops spinning.
This is the spin button event where the image spins when I click the button.
private void SpinBtn_Click(object sender, RoutedEventArgs e)
{
var ease = new PowerEase { EasingMode = EasingMode.EaseOut };
Random rng = new Random(Guid.NewGuid().GetHashCode());
//DoubleAnimation(FromValue. ToValue, Duration)
DoubleAnimation myanimation = new DoubleAnimation
(0, rng.Next(360,720), new Duration(TimeSpan.FromSeconds(3)));
//Adding Power ease to the animation
myanimation.EasingFunction = ease;
RotateTransform rotate = new RotateTransform();
img.RenderTransform = rotate;
img.RenderTransformOrigin = new Point(0.5, 0.5);
rotate.BeginAnimation(RotateTransform.AngleProperty, myanimation);
}
How do I detect the position of the image (where the pointer points) once it stops spinning? So that when the pointer is pointing to that object, I can drag and drop the words into the specific textbox.
Refer to image.
you dont need to know where the image(pointer) points,just calculate the spinning degree.
double degree = rng.Next(360, 720);
DoubleAnimation myanimation = new DoubleAnimation
(0, degree, new Duration(TimeSpan.FromSeconds(3)));
double result_degree = degree % 360;
now, you can get the target object with result_degree .
for example:
you have 12 objects in a circle like a clock,so the 1st object's degree is 0 to 29, 2nd is 30 to 59....
or you can set objects' degree by yourself, 1st is 0 to 9, 2nd is 10 to 39...
about drag and drop:
I give you a simple example:
<Grid>
<TextBox x:Name="tbResult" HorizontalAlignment="Left" AllowDrop="True" Height="23" Margin="416,245,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<TextBlock x:Name="tb1" HorizontalAlignment="Left" MouseLeftButtonDown="MyMouseLeftButtonDown" Margin="280,210,0,0" TextWrapping="Wrap" Text="ob1" VerticalAlignment="Top"/>
<TextBlock x:Name="tb2" IsEnabled="False" HorizontalAlignment="Left" MouseLeftButtonDown="MyMouseLeftButtonDown" Margin="280,245,0,0" TextWrapping="Wrap" Text="ob2" VerticalAlignment="Top"/>
<TextBlock x:Name="tb3" IsEnabled="False" HorizontalAlignment="Left" MouseLeftButtonDown="MyMouseLeftButtonDown" Margin="280,281,0,0" TextWrapping="Wrap" Text="ob3" VerticalAlignment="Top"/>
</Grid>
private void MyMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBlock tb = sender as TextBlock ;
if(tb != null && tb.IsEnabled == true)
{
switch(tb.Name)
{
case "tb1" :
DragDrop.DoDragDrop(tb1, tb1.Text, DragDropEffects.Copy);
break;
case "tb2":
DragDrop.DoDragDrop(tb2, tb2.Text, DragDropEffects.Copy);
break;
case "tb3":
DragDrop.DoDragDrop(tb3, tb3.Text, DragDropEffects.Copy);
break;
}
}
}
when you get result_degree and know which object is selected, set it's IsEnable = true and others IsEnable = false , set TextBox's AllowDrop = true.in this example, just allow user drag ob1.
I try to rotate a Border and have the MainWindow change his size based on the new space taken by the Border rotation.
I've set SizeToContent="WidthAndHeight" but window size does't take change when I rotated the border.
Do I need to programmatically set the Width and Height for the MainWindow or this can be achieved changing the xaml code in some other way?
My xaml code:
<Window x:Class="MyClass.MainWindow"
WindowStyle="None" AllowsTransparency='True'
Topmost='False' Background="Transparent" ShowInTaskbar='False'
SizeToContent="WidthAndHeight" WindowStartupLocation="Manual">
<Border Name="MyBorder"
BorderBrush="Transparent"
Background="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Top"
RenderTransformOrigin="0.5,0.5">
</Border>
</Windows>
My c# code on Window_KeyDown:
# RotateTransform rt = new RotateTransform() is declared at class level.
if (e.Key == Key.I)
{
if (rt.Angle + 1 < 360)
{
rt.Angle += 1;
}
else
{
rt.Angle = 0;
}
MyBorder.RenderTransform = rt;
}
Use LayoutTransform instead of RenderTransform
From MSDN: Transforms Overview
LayoutTransform – A transform that is applied before the layout pass. After the transform is applied, the layout system processes the
transformed size and position of the element.
RenderTransform – A transform that modifies the appearance of the element but is applied after the layout pass is complete. By using the
RenderTransform property instead of the LayoutTransform property, you
can obtain performance benefits.
Example
<Border Name="MyBorder"
BorderBrush="Transparent"
Background="Transparent"
HorizontalAlignment="Left"
VerticalAlignment="Top"
RenderTransformOrigin="0.5,0.5">
<Border.LayoutTransform>
<RotateTransform Angle="90"/>
</Border.LayoutTransform>
</Border>
So in your case
RotateTransform rt = new RotateTransform(0.0, 0.5, 0.5);
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.I)
{
if (rt.Angle + 1 < 360)
{
rt.Angle += 1;
}
else
{
rt.Angle = 0;
}
MyBorder.LayoutTransform = rt;
}
}}