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.
Related
I have few textblocks in a grid which can be dragged. I want to restrict the user so that user can't drag a textblock outside the grid.
I've tried a few ways like getting the position of the grid so that somehow i can control but it didn't work as expected.
Thanks in advance.
This can be done pretty easily using a Canvas inside the Grid, calculating the coordinates of the TextBlock inside of the Canvas and then continuously checking whether the TextBlock is still within its bounds. When the TextBlock leaves its bounds, the Transform then reverts back to it's last known 'good' coordinates.
XAML
<Grid>
<Grid Name="GridBounds" Width="600" Height="600" Background="Aqua">
<Canvas>
<TextBlock Name="TextBlock1" Text="Drag Me" FontSize="40" ManipulationDelta="TextBlock1_ManipulationDelta" ManipulationMode="TranslateX, TranslateY" HorizontalAlignment="Stretch" Canvas.Left="216" Canvas.Top="234" VerticalAlignment="Stretch"/>
</Canvas>
</Grid>
</Grid>
Code Behind
CompositeTransform TextDrag = new CompositeTransform();
CompositeTransform savedTransform = new CompositeTransform();
public MainPage()
{
this.InitializeComponent();
TextBlock1.RenderTransform = TextDrag;
}
// Copy Transform X and Y if TextBlock is within bounds
private void CopyTransform(CompositeTransform orig, CompositeTransform copy)
{
copy.TranslateX = orig.TranslateX;
copy.TranslateY = orig.TranslateY;
}
private void TextBlock1_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
TextDrag.TranslateX += e.Delta.Translation.X;
TextDrag.TranslateY += e.Delta.Translation.Y;
CompositeTransform transform = TextBlock1.RenderTransform as CompositeTransform;
// Get current Top-Left coordinates of TextBlock
var TextTopLeft = TextBlock1.TransformToVisual(GridBounds).TransformPoint(new Point(0, 0));
// Get current Bottom-Right coordinates of TextBlock
var TextBottomRight = TextBlock1.TransformToVisual(GridBounds).TransformPoint(new Point(TextBlock1.ActualWidth, TextBlock1.ActualHeight));
// Get Top-Left grid coordinates
var GridTopLeft = (new Point(0, 0));
// Get Bottom-Right grid coordinates
var GridBottomRight = (new Point(GridBounds.ActualWidth, GridBounds.ActualHeight));
if (TextTopLeft.X < GridTopLeft.X || TextBottomRight.X > GridBottomRight.X)
{
// Out of bounds on X axis - Revert to copied X transform
TextDrag.TranslateX = savedTransform.TranslateX; ;
}
else if (TextTopLeft.Y < GridTopLeft.Y || TextBottomRight.Y > GridBottomRight.Y)
{
// Out of bounds on Y axis - Revert to copied Y transform
TextDrag.TranslateY = savedTransform.TranslateY;
}
else
{
// TextBlock is within bounds - Copy X and Y Transform
CopyTransform(transform, savedTransform);
}
}
Here it is in action.
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!)
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..!
I have a textblock control on canvas which can be dragged horizontally to the right correctly as shown in the first and second image.
Then after I a 90 degree rotation angle is applied to its CompositeTransform, dragging the textblock to the right actually move it vertically towards the top as shown by the third and fourth image. What am I missing?
public CompositeTransform CurrentTransform = new CompositeTransform();
.....
TextBlock.RenderTransform = CurrentTransform;
....
private double angle;
public double Angle
{
get
{
return angle;
}
set
{
if (angle != value)
{
angle = value;
CurrentTransform.CenterX = 0;
CurrentTransform.CenterY = 0;
CurrentTransform.Rotation = angle;
}
}
}
The moving of the textbox is handled inside
private void CanvasText_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
CurrentTransform.TranslateX += e.DeltaManipulation.Translation.X;
CurrentTransform.TranslateY += e.DeltaManipulation.Translation.Y;
}
For those who are in the same boat, I managed to fix this by attaching external gesture listener from Windows Phone toolkit instead of using the built-in CanvasText_ManipulationDelta event. The textbox dragging works correctly even after rotation.
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Image x:Name="ImageOriginal"
Source="{Binding WbPreview, Mode=TwoWay}"
Stretch="Uniform"/>
<Grid x:Name="GridDraw"
Tap="GridDraw_Tap"
Background="Transparent"/>
<Canvas x:Name="CanvasText">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Tap="GestureListener_Tap"
DragDelta="GestureListener_DragDelta"/>
</toolkit:GestureService.GestureListener>
</Canvas>
</Grid>
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;
}
}}