This question already has answers here:
Make Object Follow Mouse On MouseDown and "Stick" On MouseUp
(3 answers)
Closed 2 years ago.
I am making a Space Invaders clone where you control your ship with your mouse. I found online solutions for dragging and dropping a control, which worked but I couldn't manage to translate it to just moving the control with only your mouse.
private void Window_MouseMove(object sender, MouseEventArgs e)
{
Mothership.Body.Margin = new Thickness(Mouse.GetPosition(gridSpace).X, Mouse.GetPosition(gridSpace).Y, 0, 0);
}
To clarify, I want the ship's(Image control) location to be exactly where to cursor is, without an offset. I don't even know where this offset comes from or how to get it.
Here is a screenshot of my mouse moving, you can see the image itself it very far away from the actual cursor. How do I fix this? If you need more information I will try to provide it. image
I guess that yours image control inside the grid have HorizontalAlignment="Stretch" and VerticalAlignment="Stretch" (The default values), that cause the unwanted offset. So as Clemens suggested you must use a canvas. otherwise if you can't change your parent control set the image HorizontalAlignment="Left" and VerticalAlignment="Top" and your code will be work. But as the Clemens and Ostas suggested moving a object by margin is not a good way and if you must use grid you can use a TranslateTransform (also see this).
So just set RenderTransform property of image control and set it's X and Y properties in Window_MouseMove.
Sample xaml:
<Grid x:Name="gridSpace">
<Image x:Name="Body" Source="*.png" Width="100" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image.RenderTransform>
<TranslateTransform x:Name="mTransform"/>
</Image.RenderTransform>
</Image>
</Grid>
Sample code:
private void Window_MouseMove(object sender, MouseEventArgs e)
{
//Body.Margin = new Thickness(Mouse.GetPosition(gridSpace).X, Mouse.GetPosition(gridSpace).Y, 0, 0);
Point pos = e.GetPosition(gridSpace);
mTransform.X = pos.X;
mTransform.Y = pos.Y;
}
Related
Is it possible to rotate FrameworkElement.Cursor?
My application allows user to rotate objects around their center. Once rotated, default resize cursors appear awkward on top of tilted borders.
My first thought was to apply RotateTransform to the Cursor property, but it looks like we can't do that in XAML. Next I tried inheriting from Cursor class, but it looks like MS guys have sealed it.
Another way is to set default cursor to None and use my own image (with transform) and set its position upon MouseMove. I'm not willing to go down that path if there are easier alternatives. Anyone with a good suggestion?
I'm looking for a WPF-only solution if at all possible.
Finally managed it within the bounds of WPF, without using WinForms or PInvokes. Instead of creating custom cursors (*.cur) on the fly or converting Visuals into cursors, I used MouseMove event of the parent control along with a WPF element (Path) as my cursor. Here's the way just in case anyone is interesed:
Set the Cursor of your resize thumb (or whatever you're using as the border of your shape) to None, so that WPF doesn't display default arrow.
Create your own cursor. Could be any FrameworkElement, but I have used Path for its easy manipulation to create any shape you want. Note that most of the properties I have set below are important.
<Path x:Name="PART_EW"
Data="M0,20 L25,0 25,15 75,15 75,0 100,20 75,40 75,25 25,25 25,40z"
Fill="White" Stroke="Black" StrokeThickness="1" Visibility="Collapsed"
Width="50" Height="20" Opacity=".7" Stretch="Fill" Panel.ZIndex="100001"
HorizontalAlignment="Left" VerticalAlignment="Top" IsHitTestVisible="False"
/>
Add the following code in your resize thumb:
protected override void OnMouseEnter(MouseEventArgs e)
{
base.OnMouseEnter(e);
var Pos = e.GetPosition(this);
PART_EW.Margin = new Thickness(
Pos.X - PART_EW.Width / 2,
Pos.Y - PART_EW.Height / 2,
-PART_EW.Width,
-PART_EW.Height);
PART_EW.Visibility = Visibility.Visible;
}
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
PART_EW.Visibility = Visibility.Collapsed;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var Pos = e.GetPosition(designerItem);
PART_EW.Margin = new Thickness(
Pos.X - PART_EW.Width / 2,
Pos.Y - PART_EW.Height / 2,
-PART_EW.Width,
-PART_EW.Height);
}
Note that I've not set RotateTransform of my Path anywhere in the code, since it is already part of the resize thumb and therefore acquires the angle of the parent control automatically.
Hope this helps people down the road.
I have a circle shaped button and I like to add a pair of Angel Wings to it, but I can't seem to draw it correctly.
I'd like to draw a border with an angel wing on the left and a circle in the middle and an angel wing on the right, in one custom shape..
the Custom shape is the border of the button.
The button is a resizable button, it means it can change Height & Width with the Window, and still maintain the same position.
this button is just an example of what I have made so far.
I've searched for a solution on Google and this site but can't find anything that can help me..
You can use software like Inkscape and with that you can open most image format and from images you can use the trace bitmap option to trace a path. This will create a <path> object in a <canvas>. It can then be used as a background.
things to note :
The quality highly depends on the image source quality and precision. So if your image have lots of color and gradient, huge line thickness and uses anti aliasing you will get very bad result because of a huge amount of vector on the path result. if you use thinner lines and very little color with no gradient you can get amazing conversion result.
You can also hand trace over the image and use that instead of the automatic option. You will get better result like that but it require more work.
With this path created you can create a resource in your application dictionary and use it for icon or background on anything you want. It is scalable in any direction without quality lost as it is now a vector "image".
try looking for image/Photoshop/any other image or drawing method to Xaml converter
you can create an image and convert it to xaml
see http://vectormagic.com
taken form here
Can you try this if it helps
Create Custom control , something like this
<Grid ClipToBounds="True" HorizontalAlignment="Center" VerticalAlignment="Center">
<ed:Arc x:Name="KnobA" ArcThickness="1" ArcThicknessUnit="Percent" EndAngle="360" Height="120" Stretch="None"
Stroke="Black"
StartAngle="0" Width="120" RenderTransformOrigin="0.5,0.5" StrokeThickness="0">
<ed:Arc.Fill>
<ImageBrush ImageSource="/Gazelle;component/Resources/Images/image.png" Stretch="UniformToFill" />
</ed:Arc.Fill>
</ed:Arc>
</Grid>
Use it in your other XAML
<controls:BoundRotaryButton Grid.Column="1" Margin="0,0,35,30"
VerticalAlignment="Bottom" HorizontalAlignment="Right" Opacity="0.2"
Grid.ColumnSpan="2"
BoundRotaryButtonState="{Binding myvm.RotaryPressed, Mode=OneWayToSource,
NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
Create the dependency in code behind of the button control and the handler for mouse clicks.
public static readonly DependencyProperty KnobAPushButtonStateProperty = DependencyProperty.Register("KnobAPushButtonState", typeof (bool), typeof (KnobA));
public bool KnobAPushButtonState
{
get { return (bool) GetValue(KnobAPushButtonStateProperty); }
set { SetValue(KnobAPushButtonStateProperty, value); }
}
private void KnobA_MouseDown(object sender, MouseEventArgs e)
{
Mouse.Capture(this);
KnobAPushButtonState = true;
private void KnobA_MouseUp(object sender, MouseEventArgs e)
{
Mouse.Capture(null);
KnobAPushButtonState = false;
}
In your viewmodel you will know when this dependency property changes the button is pressed or released and invoke the command you need.
I have something like a circular button, which you can rotate and press and so on. But you can use any shape you like with Blend.
I think I have some difficulty to think through. I have a canvas surrounded by a border and I want to draw a rectangle around the mouse. My problem is, the mouse can move and what I want is like a datagrid. In example, in a datagrid, all cell are already visible, (I know I can make them invisible, that's not the point), but all the cell are static, what I'm trying to do is when I mouseover the canvas, the rectangle be drawned at a static position, sorry if I'm unclear. The picture under should be better.
So as you can see in the first picture my mouse is there and I get some value, what I would like is whenever I'm in the place where I get this value I draw a rectangle over it. As you can see in the second picture when I move my mouse a little bit, I'm still in the area where I have the same value so the rectangle would still be there, and on the third picture I've moved a little further and you see the x coordinate changes and the value also do change then the rectangle would have to be drawned again over the other part
My problem is I don't know how to draw a rectangle of 45 by 40 relative to the mouse but relative to the canvas because if the mouse it's at x : 0 Y : 0 then the rectangle would be 45 by 40 but if my mouse is at X : 10 Y : 10 then the rectangle would have to be, if the mouse is the start point of 10 up the mouse down of 30 and then 10 by left and 35 to the right, I've tried to be as clear as possible, if it's still confuse tell me I will do my best.
You can achieve your requirements easily using the TranslateTransform Class and a couple of double properties:
<Rectangle Name="Rectangle" Stroke="Black" StrokeThickness="1" Fill="{x:Null}">
<Rectangle.RenderTransform>
<TranslateTransform X="{Binding XTransform}" Y="{Binding YTransform}" />
</Rectangle.RenderTransform>
</Rectangle>
You can handle the UIElement.PreviewMouseMove Event on the Canvas element and update your two transform properties from the handler... try something like this:
private void CanvasPreviewMouseMove(object sender, MouseEventArgs e)
{
XTransform = e.GetPosition(Rectangle).X;
YTransform = e.GetPosition(Rectangle).Y;
}
The MouseMove event fires whenever the mouse moves over an element. If I understand your question, you want the know where the mouse is as it moves over the Canvas. So add an event handler to the Canvas. Be sure an name the canvas, you will need the name to refer to is in the mouse event handler.
XAML
<Border Margin='20'
BorderBrush='Orange'
BorderThickness='2'>
<Canvas x:Name='DrawingCanvas'
MouseMove='DrawingCanvas_MouseMove'
Background='Transparent'>
<Rectangle x:Name='MouseRectangle'
Width='30'
Height='30'
Stroke='Purple'
StrokeThickness='2' />
</Canvas>
</Border>
The MouseMove event provides the MouseEventArgs argument. Use it to get the mouse location relative to any element in the UI. In your case, that would be the canvas.
Code
Centers the Rectangle over the mouse tip
private void DrawingCanvas_MouseMove(object sender, MouseEventArgs e) {
Canvas.SetTop(MouseRectangle,
e.GetPosition(DrawingCanvas).Y - MouseRectangle.Height/2);
Canvas.SetLeft(MouseRectangle,
e.GetPosition(DrawingCanvas).X - MouseRectangle.Width /2);
}
I have been trying to do this but I am not successful.
I have a stackpanel with a textblock in my metro app page and a grid (named : grdTheHelper, placed outside the grid) with backcolor as BLACK (so that it is visible when brought inside the page)
My requirement is that when I touch / click on the textblock in the stackpanel, the black grid takes comes exactly where I clicked.
How is this possible. I tried
Dim XY As New TranslateTransform
Private Sub MainPage_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
grdTheHelper.RenderTransform = XY
End Sub
Private Sub txt1_Tapped(sender As Object, e As TappedRoutedEventArgs) Handles txt1.Tapped
Dim AbsXY As Point
AbsXY = e.GetPosition(Me)
XY.X = AbsXY.X
XY.Y = AbsXY.Y
End Sub
But this is placing the grid say a bit too much far from where I have touched. I am clueless. Am I doing anything wrong? Is TranslateTransform only for moving the object by handling ManipulationDelta? Should Something else be used?
Please help me.
If you have XAML like this:
<Rectangle x:Name="Rect1" Fill="White" Height="100" Width="100" />
<Rectangle x:Name="Rect2" Fill="Green" Height="100" Width="100"
ManipulationMode="All"
ManipulationDelta="Rect2_ManipulationDelta_1">
<Rectangle.RenderTransform>
<CompositeTransform x:Name="Rect2Transform" />
</Rectangle.RenderTransform>
</Rectangle>
And code like this:
private void Rect2_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e)
{
Rect2Transform.TranslateX += e.Delta.Translation.X;
Rect2Transform.TranslateY += e.Delta.Translation.Y;
var _Visual = Rect2.TransformToVisual(this);
var _Location = _Visual.TransformPoint(new Point());
Rect1.SetValue(Canvas.LeftProperty, _Location.X);
Rect1.SetValue(Canvas.TopProperty, _Location.Y - 100);
}
In the code above, I keep rect2 wherever the pointer currently is on the screen. And that method then puts rect1 directly above the new position of rect2.
This demonstrates EXACTLY how to get the absolute position from either a pointer device OR relative to an object on the screen. This is the answer to your question!
XAML/C# Windows 8 app...
I have used MouseDragElementBehavior in XAML/C# to drag an element around on the screen.
Unfortunately the interactions assembly doesn't work while developing app for Windows 8.
How do I drag an element in Windows 8 XAML app?
Thanks.
EDIT: I found a sample example here: http://code.msdn.microsoft.com/windowsapps/Input-3dff271b/sourcecode?fileId=44758&pathId=962809525
Just copy the code and am able to drag my element. Having some issues will update, if need help.
You need to handle the manipulation events on the element you wish to drag. And also, set ManipulationMode to a value other than None on the element.
Handle ManipulationStarted to initialize your drag code
Handle ManipulationDelta, inspecting the e.Delta values, and offset your element using a RenderTransform, or if in a Canvas, use the canvas coordinates.
Hope that helps.
Here is a overly simplified example based on ColinE's answer.
Consider a Canvas that has an ellipse:
<Canvas Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Ellipse Fill="Red"
Canvas.Left="100"
Canvas.Top="100"
Width="100"
Height="100"
ManipulationMode="All"
ManipulationDelta="Ellipse_ManipulationDelta_1"/>
</Canvas>
Now in the code behind, you handle the ManipulationDelta:
private void Ellipse_ManipulationDelta_1(object sender, ManipulationDeltaRoutedEventArgs e)
{
Ellipse myEllipse = (Ellipse)sender;
Canvas.SetLeft(myEllipse, Canvas.GetLeft(myEllipse) + e.Delta.Translation.X);
Canvas.SetTop(myEllipse, Canvas.GetTop(myEllipse) + e.Delta.Translation.Y);
}