I have a small undecorated xaml window for a touch screen. The user must be able to move the window using touch and drag. Currently on touch and drag, the window moves in the direction of the drag, but only part way; and there appears to be two windows rather than one, making the touch and drag appear jumpy.
This behavior manifests on the development system (Surface Pro 3 using Visual Studio Professional 2015) as well as on the production system (Windows 7, no keyboard or mouse).
I based this C# on Microsoft's example.
using System.Windows;
using System.Windows.Input;
namespace XAMLApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private TouchDevice windowTouchDevice;
private Point lastPoint;
private void Circle_TouchUp(object sender, TouchEventArgs e)
{
// Do stuff.
}
private void Window_TouchDown(object sender, TouchEventArgs e)
{
e.TouchDevice.Capture(this);
if (windowTouchDevice == null)
{
windowTouchDevice = e.TouchDevice;
lastPoint = windowTouchDevice.GetTouchPoint(null).Position;
}
e.Handled = true;
}
private void Window_TouchMove(object sender, TouchEventArgs e)
{
if (e.TouchDevice == windowTouchDevice)
{
var currentTouchPoint = windowTouchDevice.GetTouchPoint(null);
var deltaX = currentTouchPoint.Position.X - lastPoint.X;
var deltaY = currentTouchPoint.Position.Y - lastPoint.Y;
Top += deltaY;
Left += deltaX;
lastPoint = currentTouchPoint.Position;
e.Handled = true;
}
}
private void Window_TouchLeave(object sender, TouchEventArgs e)
{
if (e.TouchDevice == windowTouchDevice)
windowTouchDevice = null;
e.Handled = true;
}
}
}
And here's some xaml for the window.
<Window x:Name="AppWindow" x:Class="XAMLApp.MainWindow"
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:local="clr-namespace:XAMLApp"
mc:Ignorable="d"
Title="XAML Application"
Height="25" Width="25"
AllowsTransparency="True" WindowStyle="None" ResizeMode="NoResize"
ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ShowInTaskbar="False" ToolTip="XAML Application" Topmost="True" UseLayoutRounding="True"
MaxHeight="25" MaxWidth="25" MinHeight="25" MinWidth="25"
Left="0" Top="0" Background="Transparent"
TouchDown="Window_TouchDown"
TouchMove="Window_TouchMove"
TouchLeave="Window_TouchLeave">
<Grid>
<Ellipse x:Name="Circle" Fill="Black" HorizontalAlignment="Left"
Height="24" Margin="0" Stroke="Black" VerticalAlignment="Top"
Width="24" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden"
TouchUp="Circle_TouchUp" />
</Grid>
</Window>
I've tried replacing the Grid with a Canvas. That made no difference. I also tried using Manipulation as demonstrated by Microsoft. When trying to drag the window, I was told that the transformation was invalid for the window.
How can I make the touch and drag behave the same as DragMove() using a left-mouse-click-and-drag?
The TouchPoint retrieved through the TouchDevice.GetTouchPoint method and the window's Top and Left attributes do not share the same coordinate system. All you need to do is convert the X and Y values retrieved to screen coordinates:
private void Window_TouchMove(object sender, TouchEventArgs e)
{
if (e.TouchDevice == windowTouchDevice)
{
var currentTouchPoint = windowTouchDevice.GetTouchPoint(null);
var locationOnScreen = this.PointToScreen(new Point(currentTouchPoint.Position.X, currentTouchPoint.Position.Y));
var deltaX = locationOnScreen.X - lastPoint.X;
var deltaY = locationOnScreen.Y - lastPoint.Y;
Top += deltaY;
Left += deltaX;
lastPoint = locationOnScreen;
e.Handled = true;
}
}
EDIT:
Of course, the thing about different coordinate systems applies to the whole project, so the Window_TouchDown event handler method needs to be adapted in a similar way:
private void Window_TouchDown(object sender, TouchEventArgs e)
{
e.TouchDevice.Capture(this);
if (windowTouchDevice == null)
{
windowTouchDevice = e.TouchDevice;
var currentTouchPoint = windowTouchDevice.GetTouchPoint(null);
var locationOnScreen = this.PointToScreen(new Point(currentTouchPoint.Position.X, currentTouchPoint.Position.Y));
lastPoint = locationOnScreen;
}
e.Handled = true;
}
Instead of
Top += deltaY;
Left += deltaX;
I just needed
Top += currentTouchPoint.Position.Y;
Left += currentTouchPoint.Position.X;
Ugh.
Related
I am using scroll viewer to zoom the image which is set as background for Grid.When, I am setting the zoom level value on button click from code behind with scrollViewer.ChangeView(horizontalOffset,verticalOffset,zoomFactor) image is getting zoomed from Top left corner ,not from the center position.When increasing scale level as 0.1 every time in the button click.
Find the sample here:Sample
XAML:
<UserControl Grid.Row="2">
<ScrollViewer x:Name="scrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" VerticalScrollMode="Enabled" HorizontalScrollMode="Enabled" ZoomMode="Enabled" >
<Grid x:Name="ImageGrid" VerticalAlignment="Center" HorizontalAlignment="Center" Width="1260" Height="350" >
<Image x:Name="MyImage" Width="1260" Height="210" Source="Assets\EditedImage.jpg" RenderTransformOrigin="0.5, 0.5" />
</Grid>
</ScrollViewer>
</UserControl>
C#:
float count = 1;
private void Btn_Click(object sender, RoutedEventArgs e)
{
count += 0.1f;
var width = this.scrollViewer.ExtentWidth / 2;
var height = this.scrollViewer.ExtentHeight / 2;
scrollViewer.ChangeView(width, height, count);
}
You must calculate the offset relative to the scrollable area.
XAML
<StackPanel>
<Button Click="ZoomIn_OnButtonClick" Content="Increase Zoom"/>
<ScrollViewer x:Name="ScrollViewer"
HorizontalScrollBarVisibility="Visible"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<Image Stretch="Uniform" Source="Assets\golden_eaglew.jpg" />
</ScrollViewer>
</StackPanel>
Solution using ScrollViewer.ChangeView
Since the scroll viewer's extent changes as a result of applying the zoom and the zoom is applied after the scroll offsets are applied, you have to defer the scrolling to the center by making use of the ScrollViewer.ViewChanged event. This is because the scrollable area is influenced by the extent's size (e.g. ScrollableWidth = ExtentWidth - ViewportWidth).
public MainPage()
{
this.InitializeComponent();
this.ScrollViewer.ViewChanged += ScrollToCenterOnScrollViewerChanged;
}
private void ScrollToCenterOnScrollViewerChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
if (e.IsIntermediate)
{
return;
}
var scrollViewer = sender as ScrollViewer;
scrollViewer.ChangeView(
scrollViewer.ScrollableWidth / 2,
scrollViewer.ScrollableHeight / 2,
null);
}
private void ZoomIn_OnButtonClick(object sender, RoutedEventArgs e)
=> this.ScrollViewer.ChangeView(null, null, this.ScrollViewer.ZoomFactor + 0.1f);
Alternative Solution 1: use ScrollViewer.ZoomToFactor
Note that this API is marked as deprecated and is not guaranteed to be available in future framework versions.
private void ZoomIn_OnButtonClick(object sender, RoutedEventArgs e)
{
this.ScrollViewer.ZoomToFactor(this.ScrollViewer.ZoomFactor + 0.1f);
this.ScrollViewer.ScrollToHorizontalOffset(this.ScrollViewer.ScrollableWidth / 2);
this.ScrollViewer.ScrollToVerticalOffset(this.ScrollViewer.ScrollableHeight / 2);
}
Alternative Solution 2: implement a custom ZoomToFactor method
private void ZoomToFactor(double zoomFactor, ScrollViewer scrollViewer)
{
if (!(scrollViewer?.Content is FrameworkElement zoomTarget))
{
return;
}
// Apply the zoom to the scroll content
zoomTarget.Width = zoomTarget.ActualWidth * zoomFactor;
zoomTarget.Height = zoomTarget.ActualHeight * zoomFactor;
// Scroll the zoomed scroll content to center
var scaledScrollableWidth = scrollViewer.ExtentWidth * zoomFactor - scrollViewer.ViewportWidth);
var scaledScrollableHeight = scrollViewer.ExtentHeight * zoomFactor - scrollViewer.ViewportHeight;
double horizontalScrollCenterOffset = scaledScrollableWidth / 2;
double verticalScrollCenterOffset = scaledScrollableHeight / 2;
scrollViewer.ScrollToHorizontalOffset(horizontalScrollCenterOffset);
scrollViewer.ScrollToVerticalOffset(verticalScrollCenterOffset);
}
// Usage example
private void ZoomIn_OnButtonClick(object sender, RoutedEventArgs e)
{
ZoomToFactor(1.1, this.ScrollViewer);
}
I am trying to drag a shape inside a scroll viewer.
My solution was to temporarily disable the scroll viewer when touching the shape, then re-enabling when releasing. Feels a bit hacky, but couldn't find a better solution. Has anyone a better recommendation?
The XAML code below.
<Page
x:Class="testdragshape.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:testdragshape"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Height="390.667">
<Grid>
<ScrollViewer Name="scrollViewer" >
<Grid Name="pageGrid">
<TextBlock Name="log" Text="Position:"/>
<Canvas Name="myCanvas" Width="500" Height="500">
<Rectangle Name="myTarget" Width="272" Height="272" Fill="Red" Canvas.Left="41" Canvas.Top="53" />
</Canvas>
</Grid>
</ScrollViewer>
</Grid>
The C# UWP code below
using Windows.Foundation;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
namespace testdragshape
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
myCanvas.RenderTransform = new TranslateTransform();
myTarget.PointerPressed += Target_PointerPressed;
myTarget.PointerMoved += Target_PointerMoved;
myTarget.PointerReleased += MyTarget_PointerReleased;
}
Point _drag0;
private void Target_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// disable the scroll mode
scrollViewer.HorizontalScrollMode = ScrollMode.Disabled;
scrollViewer.VerticalScrollMode = ScrollMode.Disabled;
_drag0 = e.GetCurrentPoint(myCanvas).Position;
log.Text = "Position - X: " + _drag0.X + " Y: " + _drag0.Y;
}
private void Target_PointerMoved(object sender, PointerRoutedEventArgs e)
{
if (!e.Pointer.IsInContact) return;
var point = e.GetCurrentPoint(myCanvas).Position;
var t = new Point(point.X - _drag0.X, point.Y - _drag0.Y);
TranslateTransform previous = (TranslateTransform)myCanvas.RenderTransform;
myCanvas.RenderTransform = new TranslateTransform()
{
X = previous.X + t.X,
Y = previous.Y + t.Y
};
log.Text = "Position - X: " + point.X + " Y: " + point.Y;
}
private void MyTarget_PointerReleased(object sender, PointerRoutedEventArgs e)
{
// re-enable scroll mode
scrollViewer.HorizontalScrollMode = ScrollMode.Auto;
scrollViewer.VerticalScrollMode = ScrollMode.Auto;
}
}
}
You are almost there, except you should disable the direct manipulation of ScrollViewer instead of disabling scrolling, and re-enable it once you are done.
private void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
scrollViewer.CancelDirectManipulations();
}
private void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
TryStartDirectManipulation(e.Pointer);
}
I need help correcting either my thumb drag or my animation after the dragging. The steps I basically want is:
user left-clicks on the scroll handle and drags handle+image
horizontally across the window.
the handle+image will either snap to the left window edge, or the handle
will snap to the right window edge with the image hidden to the
right
if the user release the left click while dragging, the
handle+image will continue on the direction its going to either the
left or right window edge and snaps to that, c.f. #2
Now, upon loading, it is working as I want, but for the subsequent drags, the thumb dragging visibility is gone. It just jumps to where I release the left click and continue the snapping animation from there.
I've tried various workarounds, to the best of my ability, but nothing seems to be the solution. Minimal code is as below.
MainWindow.xaml
<Window x:Class="TouchSample.MainWindow"
Name="Window_TouchSample"
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:local="clr-namespace:TouchSample"
mc:Ignorable="d"
Title="MainWindow"
Height="600" Width="600"
xmlns:custom="clr-namespace:TouchSample">
<Grid Name="Grid_TouchableThing">
<custom:TouchableThing />
</Grid>
</Window>
TouchableThing.xaml
<UserControl x:Class="TouchSample.TouchableThing"
Name="Scroll_UserControl"
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:local="clr-namespace:TouchSample"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="600">
<Canvas x:Name="Scroll_Canvas">
<Thumb Name="Scroll_thumb"
Canvas.Left="20"
Canvas.Top="120"
Canvas.ZIndex="3"
DragDelta="Thumb_DragDelta"
PreviewMouseLeftButtonUp="Scroll_thumb_PreviewMouseLeftButtonUp">
<Thumb.Template>
<ControlTemplate>
<StackPanel Name="Scroll_thumb_StackPanel"
Orientation="Horizontal">
<Border Name="Scroll_thumb_StackPanel_Border" Background="Black" Padding="1">
<TextBlock Name="Scroll_thumb_StackPanel_Border_TextBlock"
Text="Scroll"
Background="Silver"
TextAlignment="Center"
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"
>
<TextBlock.LayoutTransform>
<RotateTransform Angle="90"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Border>
<Button Background="Yellow" Padding="1">
<Image Name="Scroll_thumb_StackPanel_Button_Image" Source="Assets/long-ancient-scroll-4499037_x4.jpg" />
</Button>
</StackPanel>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Canvas>
</UserControl>
TouchableThing.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace TouchSample
{
/// <summary>
/// Interaction logic for TouchableThing.xaml
/// </summary>
public partial class TouchableThing : UserControl
{
private double toLeftValue = 0;
private double toRightValue = 550; // will get overwritten in OnWindowSizeChanged
private bool isGoingLeft = false;
private bool isGoingRight = false;
private double lastDiffX;
public TouchableThing()
{
InitializeComponent();
this.SizeChanged += OnWindowSizeChanged;
}
private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e)
{
//throw new NotImplementedException();
//Console.WriteLine("sender: " + sender.ToString());
//Console.WriteLine("sender.GetType(): " + sender.GetType().ToString());
//Console.WriteLine("e: " + e.ToString());
toRightValue = e.NewSize.Width;
var aBorder = VisualHierarchyHelper.FindChild<Border>(Scroll_thumb, "Scroll_thumb_StackPanel_Border");
if (aBorder != null)
{
Console.WriteLine("aBorder.ActualWidth: " + aBorder.ActualWidth.ToString());
Console.WriteLine("aBorder.RenderSize.Height: " + aBorder.RenderSize.Height.ToString());
toRightValue -= aBorder.ActualWidth;
}
Console.WriteLine("toRightValue=" + toRightValue.ToString());
}
// https://wpf.2000things.com/2012/12/19/715-using-the-thumb-control-to-drag-objects-on-a-canvas/
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
//UIElement thumb = e.Source as UIElement;
UIElement thumb = sender as UIElement;
double xChange = Canvas.GetLeft(thumb) + e.HorizontalChange;
if(xChange >= toLeftValue && xChange <= toRightValue)
{
Canvas.SetLeft(thumb, xChange);
//Canvas.SetTop(thumb, Canvas.GetTop(thumb) + e.VerticalChange);
//Console.WriteLine("e.HorizontalChange=" + e.HorizontalChange);
if (e.HorizontalChange > 0)
{
isGoingLeft = false;
isGoingRight = true;
}
else if (e.HorizontalChange < 0)
{
isGoingLeft = true;
isGoingRight = false;
}
else
{
isGoingLeft = false;
isGoingRight = false;
}
lastDiffX = xChange;
}
}
private void goLeft(UIElement theUIElement, double fromX)
{
DoubleAnimation goLeftAnim = new DoubleAnimation();
goLeftAnim.From = fromX;
goLeftAnim.To = toLeftValue;
goLeftAnim.Duration = new Duration(TimeSpan.FromSeconds(2));
theUIElement.BeginAnimation(Canvas.LeftProperty, goLeftAnim);
}
private void goRight(UIElement theUIElement, double fromX)
{
DoubleAnimation goRightAnim = new DoubleAnimation();
goRightAnim.From = fromX;
goRightAnim.To = toRightValue;
goRightAnim.Duration = new Duration(TimeSpan.FromSeconds(2));
theUIElement.BeginAnimation(Canvas.LeftProperty, goRightAnim);
}
private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
TextBlock aTextBlock = sender as TextBlock;
//Console.WriteLine("TextBlock_MouseLeftButtonDown: Changing TextBlock Background colour to Gray");
aTextBlock.Background = Brushes.Gray;
}
private void Scroll_thumb_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var aTextBlock = VisualHierarchyHelper.FindChild<TextBlock>(Scroll_thumb, "Scroll_thumb_StackPanel_Border_TextBlock");
if (Mouse.LeftButton == MouseButtonState.Released && aTextBlock != null)
{
//Console.WriteLine("Scroll_thumb_PreviewMouseLeftButtonUp: Changing TextBlock Background colour to Silver");
//Console.WriteLine(" found aTextBlock");
aTextBlock.Background = Brushes.Silver;
}
if (isGoingLeft)
goLeft(Scroll_thumb, lastDiffX);
else if (isGoingRight)
goRight(Scroll_thumb, lastDiffX);
}
}
}
I'm just starting with WPF with just a year's experience on C# and WinForms, so any help is greatly appreciated.
Sryn
I asked this same question on MSDN and a moderator there, Yohann Lu, gave a working code for my requirements. S/He mentioned that I needed to 'clear the animation' by using this code
theUIElement.BeginAnimation(Canvas.LeftProperty, null);
The thread containing the complete code is at the link below
https://social.msdn.microsoft.com/Forums/en-US/863c85e5-f372-4439-b3dc-f37623665e3a/c-animating-a-thumb?forum=wpf
Thank you Yohann and to anybody who attempted this.
Sryn
How move ellipse by mouse on window in WPF.
private void ellipse_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
Ellipse ellipse = sender as Ellipse;
if (ellipse != null && e.LeftButton == MouseButtonState.Pressed)
{
DragDrop.DoDragDrop(ellipse,
ellipse.Fill.ToString(),
System.Windows.DragDropEffects.Copy);
}
}
How to create method ellipse_MouseClick?
There is no MouseClick event on Ellipses, however there is the MouseDown and MouseUp events. I assume you are looking for something like this.
WPF:
<Window x:Class="WpfApplication.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525"
MouseMove="Any_MouseMove"
>
<Canvas>
<Ellipse Fill="Lavender" Height="100" Width="100"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp"
MouseMove="Any_MouseMove" />
</Canvas>
</Window>
Code Behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication
{
public partial class MainWindow : Window
{
private UIElement _lastClickedUIElement;
private Point? _clickOffset;
public MainWindow() { InitializeComponent(); }
private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_lastClickedUIElement = sender as UIElement;
_clickOffset = e.GetPosition(_lastClickedUIElement);
}
private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_lastClickedUIElement = null;
}
private void Any_MouseMove(object sender, MouseEventArgs e)
{
if (_lastClickedUIElement == null)
return;
_lastClickedUIElement.SetValue(Canvas.LeftProperty, e.GetPosition(this).X - _clickOffset.Value.X);
_lastClickedUIElement.SetValue(Canvas.TopProperty, e.GetPosition(this).Y - _clickOffset.Value.Y);
}
}
}
Click on the circle to move it around. This will work on any UI element as long as long as you give them those methods. feel free to add a Rectangle to the canvas also.
<Rectangle Fill="Lavender" Height="100" Width="100"
MouseLeftButtonDown="Ellipse_MouseLeftButtonDown"
MouseLeftButtonUp="Ellipse_MouseLeftButtonUp"
MouseMove="Any_MouseMove" />
I use three events to accomplish this task:
XAML:
<Window x:Class="WpfPainting.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="700" WindowStartupLocation="CenterScreen">
<DockPanel>
<Canvas Background="White" Name="CanvasArea"/>
</DockPanel>
</Window>
Code:
private UIElement source;
private bool captured;
double x_shape, x_canvas, y_shape, y_canvas;
private void ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Mouse.OverrideCursor = Cursors.SizeAll;
source = (UIElement)sender;
Mouse.Capture(source);
captured = true;
x_shape = Canvas.GetLeft(source);
x_canvas = e.GetPosition(CanvasArea).X;
y_shape = Canvas.GetTop(source);
y_canvas = e.GetPosition(CanvasArea).Y;
}
private void ellipse_MouseMove(object sender, MouseEventArgs e)
{
if (captured)
{
double x = e.GetPosition(CanvasArea).X;
double y = e.GetPosition(CanvasArea).Y;
x_shape += x - x_canvas;
Canvas.SetLeft(source, x_shape);
x_canvas = x;
y_shape += y - y_canvas;
Canvas.SetTop(source, y_shape);
y_canvas = y;
}
}
private void ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
captured = false;
Mouse.OverrideCursor = null;
}
To use the events on a painted ellipse I refer to them like this:
ellipse.MouseLeftButtonDown += conveyor_MouseLeftButtonDown;
ellipse.MouseMove += conveyor_MouseMove;
ellipse.MouseLeftButtonUp += conveyor_MouseLeftButtonUp;
Well, because I have nothing better else to do than getting familiar with C# and WPF I decided to make some simple app with graph with visualisation. So I want to put "nodes" on canvas, and move it, connect by edges e.t.c.
But I don't know how to detect if some "node" is clicked.
I noticed that there's .MouseDown in Ellipse object but don't know how to use it (just if (ellipse.MouseDown) is mot correct) in this situation
xaml:
<Window x:Class="GraphWpf.View"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="View" Height="400" Width="700" ResizeMode="NoResize">
<Grid>
<Canvas x:Name="canvas" MouseDown="Canvas_MouseDown" Background="#227FF2C5" Margin="0,0,107,0" />
<CheckBox Content="Put nodes" Height="32" HorizontalAlignment="Left" Margin="591,67,0,0" Name="putNodes" VerticalAlignment="Top" Width="75" />
</Grid>
</Window>
cs code:
public partial class View : Window
{
public View()
{
InitializeComponent();
}
private Point startPoint;
private Ellipse test;
List<Ellipse> nodesOnCanv = new List<Ellipse>();
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(canvas);
if ((bool)putNodes.IsChecked)
{
test = new Ellipse();
test.Fill = new SolidColorBrush(Colors.Blue);
test.Width = 20;
test.Height = 20;
var x = startPoint.X;
var y = startPoint.Y;
Canvas.SetLeft(test, x);
Canvas.SetTop(test, y);
canvas.Children.Add(test);
nodesOnCanv.Add(test);
}
else {
foreach(Ellipse element in nodesOnCanv){ //such statment is incorrect
if (element.MouseDown()) {
//do something
}
}
}
}
}
You could use IsMouseOver Property
foreach (Ellipse element in nodesOnCanv)
{
if (element.IsMouseOver)
{
element.Fill = Brushes.Red;
}
}
or handle MouseDown for each node
test = new Ellipse();
test.MouseDown += new MouseButtonEventHandler(test_MouseDown);
.
void test_MouseDown(object sender, MouseButtonEventArgs e)
{
(sender as Ellipse).Fill = Brushes.Red;
}
I would prefer the latter.