//xaml <Window x:Class="WpfApp58.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:behavior="http://schemas.microsoft.com/xaml/behaviors" WindowState="Maximized" xmlns:local="clr-namespace:WpfApp58" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="Closed"> <behavior:InvokeCommandAction Command="{Binding CloseWindowCommand}"/> </behavior:EventTrigger> </behavior:Interaction.Triggers> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition Height="50"/> </Grid.RowDefinitions> <Canvas Grid.Row="0" x:Name="cvs" Height="{Binding ActualHeight,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}" Width="{Binding ActualWidth,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Window}}}" > <behavior:Interaction.Triggers> <behavior:EventTrigger EventName="MouseDown"> <behavior:InvokeCommandAction Command="{Binding MouseDownCommand}" PassEventArgsToCommand="True"/> </behavior:EventTrigger> <behavior:EventTrigger EventName="MouseUp"> <behavior:InvokeCommandAction Command="{Binding MouseUpCommand}" PassEventArgsToCommand="True"/> </behavior:EventTrigger> <behavior:EventTrigger EventName="MouseMove"> <behavior:InvokeCommandAction Command="{Binding MouseMoveCommand}" PassEventArgsToCommand="True"/> </behavior:EventTrigger> </behavior:Interaction.Triggers> </Canvas> <StatusBar Grid.Row="1"> <StatusBarItem> <TextBlock Text="{Binding StatusStr,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" FontSize="20"/> </StatusBarItem> </StatusBar> </Grid> </Window> //cs using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Media.TextFormatting; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace WpfApp58 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var vm = new CanvasVM(cvs); this.DataContext = vm; } private void cvs_MouseDown(object sender, MouseButtonEventArgs e) { } private void cvs_MouseUp(object sender, MouseButtonEventArgs e) { } private void cvs_MouseMove(object sender, MouseEventArgs e) { } } public class CanvasVM : INotifyPropertyChanged { Canvas cvs; Random rnd { get; set; } Ellipse elp { get; set; } double width, height; private bool isMoving = false; private bool isCopy = false; private int idx = 0; public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propName) { var handler = PropertyChanged; if (handler != null) { handler?.Invoke(this, new PropertyChangedEventArgs(propName)); } } private string statusStr; public string StatusStr { get { return statusStr; } set { if (value != statusStr) { statusStr = value; OnPropertyChanged(nameof(StatusStr)); } } } private Ellipse capturedElp { get; set; } public CanvasVM(Canvas cvsValue) { cvs = cvsValue; InitData(); InitCommands(); } private void InitData() { width = cvs.ActualWidth; height = cvs.ActualHeight; rnd = new Random(); elp = new Ellipse(); elp.Width = 100; elp.Height = 100; elp.ToolTip = ++idx; elp.Stroke = new SolidColorBrush(Colors.Blue); elp.Fill = new SolidColorBrush(Colors.Red); elp.StrokeThickness = 5; Canvas.SetLeft(elp, rnd.Next(0, (int)width)); Canvas.SetTop(elp, rnd.Next(0, (int)height)); if (!cvs.Children.Contains(elp)) { cvs.Children.Add(elp); } } private void InitCommands() { MouseDownCommand = new DelCommand(MouseDownCommandExecuted); MouseUpCommand = new DelCommand(MouseUpCommandExecuted); MouseMoveCommand = new DelCommand(MouseMoveCommandExecuted); CloseWindowCommand = new DelCommand(CloseWindowCommandExecuted); } private void CloseWindowCommandExecuted(object obj) { var msgResult = MessageBox.Show("Are you sure to exit?", "Exit", MessageBoxButton.YesNo, MessageBoxImage.Information, MessageBoxResult.Yes); if (msgResult == MessageBoxResult.Yes) { Application.Current?.Shutdown(); } } private void MouseMoveCommandExecuted(object obj) { var e = obj as MouseEventArgs; var pt = e.GetPosition(cvs); Application.Current.Dispatcher.BeginInvoke(new Action(() => { StatusStr = $"{pt.X},{pt.Y}"; })); if (e == null) { return; } if (Keyboard.Modifiers == ModifierKeys.Control && Keyboard.IsKeyDown(Key.C) && Mouse.LeftButton == MouseButtonState.Pressed) { isCopy = true; } else if(Keyboard.Modifiers == ModifierKeys.Control && Mouse.LeftButton==MouseButtonState.Released) { capturedElp = Mouse.Captured as Ellipse; isMoving = true; } e.Handled = true; } private void MouseUpCommandExecuted(object obj) { var e = obj as MouseButtonEventArgs; if (e == null) { return; } var pt = e.GetPosition(cvs); if (Keyboard.Modifiers == ModifierKeys.Control && Mouse.LeftButton == MouseButtonState.Released && isCopy) { Ellipse elp = new Ellipse(); elp.Width = 100; elp.Height = 100; elp.ToolTip = ++idx; elp.Stroke = new SolidColorBrush(Colors.Blue); elp.Fill = new SolidColorBrush(Colors.Red); elp.StrokeThickness = 5; Canvas.SetLeft(elp, pt.X); Canvas.SetTop(elp, pt.Y); if (!cvs.Children.Contains(elp)) { cvs.Children.Add(elp); } isCopy = false; } if (isMoving) { if (capturedElp != null && isMoving) { Canvas.SetLeft(capturedElp, pt.X); Canvas.SetTop(capturedElp, pt.Y); } isMoving = false; } e.Handled = true; } private void MouseDownCommandExecuted(object obj) { var e = obj as MouseEventArgs; cvs.CaptureMouse(); Mouse.Capture(elp); e.Handled = true; } public DelCommand MouseDownCommand { get; set; } public DelCommand MouseUpCommand { get; set; } public DelCommand MouseMoveCommand { get; set; } public DelCommand CloseWindowCommand { get; set; } public List<Visual> FindVisualChildren(DependencyObject dpObj) { List<Visual> childrenList = new List<Visual>(); int childrenCount = VisualTreeHelper.GetChildrenCount(dpObj); for (int i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(dpObj, i) as Visual; if (child != null) { childrenList.Add(child); childrenList.AddRange(FindVisualChildren(child)); } } return childrenList; } } public class DelCommand : ICommand { private Action<object> execute; private Predicate<object> canExecute; public DelCommand(Action<object> executeValue, Predicate<object> canExecuteValue = null) { this.execute = executeValue; this.canExecute = canExecuteValue; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { if (canExecute == null) { return true; } return canExecute(parameter); } public void Execute(object parameter) { execute(parameter); } } }