【问题标题】:I've created a ellipse in c#...bt i want to move ellipse around the canvas using mouse.....can anyone help? And i'm new to c# [closed]我在 C# 中创建了一个椭圆...bt 我想用鼠标在画布上移动椭圆.....有人可以帮忙吗?我是 C# 的新手 [关闭]
【发布时间】:2016-11-14 16:15:15
【问题描述】:

我在 c# 中创建了一个椭圆,但我想使用鼠标在画布上移动椭圆。任何人都可以帮忙吗?我是 C# 新手。

这是我的代码。

private Ellipse drawEllipse(Canvas aCanvas)
    {
        Ellipse newEllipse = new Ellipse();
        newEllipse.Width = 10;
        newEllipse.Height = 10;
        newEllipse.Fill = new SolidColorBrush(Colors.RoyalBlue);
        aCanvas.Children.Add(newEllipse);
        newEllipse.SetValue(Canvas.LeftProperty, aCanvas.ActualWidth / 2.0);
        newEllipse.SetValue(Canvas.TopProperty, aCanvas.ActualHeight / 2.0);
        return newEllipse;


    }

【问题讨论】:

  • 您的目标是什么:Winforms、WPF、ASP..? 始终正确标记您的问题!
  • WPF........我知道如何移动在 xaml 代码中创建的椭圆..bt 我已经使用 c# 创建了它,所以我该如何移动它?我尝试应用相同的 mouseleftbuttondown 和 up 功能。bt 它可以解决..
  • 好吧..我自己解决了这个问题..bt m 面临新问题...nw 我已经创建了一个椭圆,我可以使用鼠标将它移动到画布上的任何位置... nw 我想在椭圆内给出 num(label ellipse with num),就像圆圈内的数字一样……当我使用鼠标移动椭圆时,这个 num 应该与椭圆一起移动……我该怎么做?这可能吗? @TaW
  • 对不起我的朋友,但由于我不使用 WPF,我无能为力..
  • @Vivek Bhat 您应该在椭圆和标签(都在同一个绑定类或匹配的 ID 系统等中)之间建立概念联系,并对椭圆应用所有修改(取决于您用来移动它的方法:坐标绑定、变换等)到相应的标签(在鼠标事件中)。

标签: c# wpf canvas drawellipse


【解决方案1】:

我也是 WPF 的新手,所以我将向您解释到目前为止我所了解的内容以及如何制作椭圆。由于我也是 WPF 初学者,我的解释有时可能是近似值,所以请不要把我活活烧死。这篇文章可能很长​​p>

WPF 和 MVVM

首先,您有一个“视图”,它是 XAML 代码(一种具有类似 XML 语法的描述语言。每个标记对应于 .NET Framework 中的一个类)并设计您将看到的所有内容。使用 WPF 时,您应该尝试实现 MVVM 模式。在这种模式中,窗口的设计不是 C# 代码的问题,而是“视图”组件的问题,即 XAML 代码。您有一个“ViewModel”组件来准备将成为视图参数的数据。最后一个组件是模型,它后面的所有东西都与用户界面无关。

使用 C# 编码视图(就像您所做的那样)被称为“代码隐藏”,在大多数情况下是 MVVM 模式错误。

View 被“绑定”到 ViewModel。绑定后,视图知道 ViewModel 类并可以使用它的字段和属性。使用视图模型的最大好处是,当您修改绑定到视图的 ViewModel 中的变量时,它会自动更新视图。

绘制和拖放和椭圆

这里是一个椭圆视图的例子:

在 CanvasOverlayView.xaml 中

<UserControl x:Class="Overlay.Views.CanvasOverlayView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:viewModels="clr-namespace:Overlay.ViewModels"
             d:DataContext="{d:DesignInstance Type=viewModels:CanvasOverlayViewModel}"
             mc:Ignorable="d">




//You can declare a mouse event like this, with the appropriate event handlers in the .xaml.cs file 

//  <Canvas MouseDown="UIElement_OnMouseDown" MouseMove="UIElement_OnMouseMove" MouseUp="UIElement_OnMouseUp">





// however I use a completely separated file as ViewModel so i will use this :
     <i:Interaction.Triggers>
                        <i:EventTrigger EventName="MouseDown">


                 <i:InvokeCommandAction Command="{Binding Path=DataContext.MouseDownCommand}"
                                           CommandParameter="{Binding ElementName=CanvasOverlayView}"/>
                    </i:EventTrigger>

                    <i:EventTrigger EventName="MouseUp">
                        <i:InvokeCommandAction Command="{Binding Path=DataContext.MouseUpCommand}"
                                           CommandParameter="{Binding ElementName=CanvasOverlayView}"/>
                    </i:EventTrigger>

                    <i:EventTrigger EventName="MouseMove">
                        <i:InvokeCommandAction Command="{Binding Path=DataContext.MouseMoveCommand}"
                                           CommandParameter="{Binding ElementName=CanvasOverlayView}"/>
                    </i:EventTrigger>
                    <Path Stroke="{Binding Color}" StrokeThickness="{Binding Thickness}">
                        <Path.Data>
                            <EllipseGeometry
                                Center="{Binding Center}"
                                RadiusX="{Binding RadiusX}"
                                RadiusY="{Binding RadiusY}"/>
                        </Path.Data>
                    </Path>
    </Canvas>

到详情:

x:Class="Overlay.Views.CanvasOverlayView"

准确的关联 CanvasOverlayView.xaml.cs 的名称(如果我理解正确,它是绘制 xaml 文件描述的内容所需的 C# 的部分类)。您可以将此文件用作 ViewModel,但最好在一个完全分离的文件中执行此操作,这就是我将在此示例中执行的操作。因此 xaml.cs 几乎是空的(设置 datacontext 和初始化组件)。

xmlns:viewModels="clr-namespace:Overlay.ViewModels"

将我的所有 ViewModel 命名为 viewModels 的命名空间。这用于在下一行查找 ViewModel

d:DataContext="{d:DesignInstance Type=viewModels:CanvasOverlayViewModel}" DataContext 是绑定操作将获取其数据的类实例。在这里,我将 DataContext(如果需要,我的参数的来源)设置为正确的视图模型。每个视图都有自己的 ViewModel

Interaction.Triggers 在这里,我将为 Command 创建触发器。该命令将允许我在我的 ViewModel 中处理我的事件(如果我使用 xaml.cs 作为视图模型而不是完全独立的 .cs 文件,我不需要这个)。

注意绑定语法,这是你使用来自视图模型的“”“参数”“”。

路径和椭圆几何

绘制椭圆的方法之一。我使用这种方式是因为我更喜欢使用椭圆的中心和半径而不是 Canvas.SetLeft、Width、Height 等...这使得拖动操作更容易(只需要在 viewmodel 和 tadaaaam 中更新中心,椭圆移动) .

在 CanvasOverlayView.xaml.cs 中

namespace Overlay.Views
{
    public partial class CanvasOverlayView
    {
        public CanvasOverlayView()
        {
            DataContext = new CanvasOverlayViewModel();
            InitializeComponent();
        }    
    }
}

这里我给出了一个 ViewModel 的实例作为 DataContext。

在 CanvasOverlayViewModel.cs 中

首先也是最重要的事情:ViewModel 必须实现 INotifyPropertyChanged 接口。这个接口是必不可少的,因为这是使您的绑定属性自动更新视图的原因。这是一个在属性中使用示例的最小实现。

using System.ComponentModel;
    namespace Overlay.ViewModels
    {    
     public class CanvasOverlayViewModel : INotifyPropertyChanged
     {
       private int exemple;
       public int Exemple
       {
         get 
         {
            return exemple;
         }
         set
         {
           exemple = value;
           OnPropertyChanged(nameof(Exemple));  // IMPORTANT
         }
       } 

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName) => 
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

有了这个,如果你的 xaml 中有一个“{Binding Example}”,当你在 ViewModel 中更改 Example 值时,它会自动更新。

对于您的椭圆,您可以创建一个包含椭圆的所有参数的类,在 ViewModel 中实例化它并将其绑定到您的视图中。

命令和事件

这里是一个使用 Command 处理事件的示例,用于上面的 View 示例。当然,这不是使用 ICommand 的唯一方法。

private ICommand m_MouseDownCommand;
private ICommand m_MouseMoveCommand;
private ICommand m_MouseUpCommand;
private bool CanMove
private Point center; // binded to the center property of EllipseGeometry in View.

public Point Center
{
   get
   {
     return center;
   }
   set
   {
     center = value;
     OnPropertyChanged(nameof(Exemple));
   }
}

// first parameter is the method that handle the event, the second is a bool method that define if the event is triggerable.
// DelegateCommand is a custom class implementing ICommand, i'll give code below.

public ICommand MouseDownCommand => m_MouseDownCommand ?? (m_MouseDownCommand = new DelegateCommand(OnMouseDown, CanMouseDown));

public ICommand MouseMoveCommand => m_MouseMoveCommand ?? (m_MouseMoveCommand = new DelegateCommand(OnMouseMove, CanMouseMove));

public ICommand MouseUpCommand => m_MouseUpCommand ?? (m_MouseUpCommand = new DelegateCommand(OnMouseUp, CanMouseUp));


private bool CanMouseDown(object parameter)
{
   return true;
}

private bool CanMouseMove(object parameter)
{
   return CanMove;
}

private bool CanMouseUp(object parameter)
{
   return true;
}

private void OnMouseDown(object parameter)
{
   CanMove = true;
}   


private void OnMouseMove(object parameter)
{
   // EllipseGeometry Center property is updated !
   Center = Mouse.GetPosition((IInputElement)parameter);
}


private void OnMouseUp(object parameter)
{ 
   CanMove = false;
}   

我会给你我的 DelegateCommand 类:

using System;
using System.Windows.Input;

    public class DelegateCommand : ICommand
    {
        private readonly Action<object> m_command;

        private readonly Predicate<object> m_canExecute;

        public DelegateCommand(Action<object> command, Predicate<object> canExecute = null)
        {
            if (command == null)
            {
                throw new ArgumentNullException("command", "The delegate command is null");
            }

            m_canExecute = canExecute;
            m_command = command;
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                CommandManager.RequerySuggested += value;
            }

            remove
            {
                CommandManager.RequerySuggested -= value;
            }
        }

        public void Execute(object parameter)
        {
            m_command(parameter);
        }

        public bool CanExecute(object parameter)
        {
            return m_canExecute == null || m_canExecute(parameter);
        }
    }

我希望我的解释很清楚。抱歉,如果它在技术上不是 200% 准确,我也是 WPF 的新手。这是许多方法中的一种,可能不是最好的。 有什么不清楚的地方告诉我,或者可以说得更准确些。

【讨论】:

  • 非常感谢,它正在工作..但我可以说它有点复杂或冗长......是的,它确实有效..所以再次感谢你的帮助......我'如果我找到更好的解决方法,我会在这里更新...@Csi
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多