0

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;


    }
4

1 に答える 1

0

私はWPFも初めてなので、これまでに理解したことと、楕円を作成する方法を説明します。私もWPFの初心者なので、私の説明はおおよそのものかもしれませんので、私を燃やさないでください。この投稿は長くなる可能性があります

WPF と MVVM

まず、XAML コード (XML に似た構文を持つ記述言語。各タグは .NET Framework のクラスに対応する) である "ビュー" を用意し、表示されるすべてのものを設計します。WPF を使用する場合は、MVVM パターンの実装を試みる必要があります。このパターンでは、ウィンドウのデザインは C# コードの問題ではなく、XAML コードである "View" コンポーネントの問題です。ビューの一種のパラメーターとなるデータを準備する「ViewModel」コンポーネントがあります。最後のコンポーネントはモデルであり、その背後にあるすべてのものはユーザー インターフェイスとは何の関係もありません。

(あなたがしたように) C# でビューをコーディングすることは「コードビハインド」と呼ばれ、ほとんどの場合 MVVM パターンの間違いです。

View は ViewModel に「バインド」されています。バインドされると、View は 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 でイベントを処理できます (完全に別の .cs ファイルではなく、xaml.cs をビューモデルとして使用した場合、これは必要ありません)。

Binding 構文に注意してください。これは、viewmodel から取得した """parameters""" を使用した場合です。

パスと EllipseGeometry

楕円を描く方法の 1 つ。Canvas.SetLeft、Width、Height などではなく、楕円の中心と半径を操作することを好んだため、この方法を使用します...これにより、ドラッグ操作が簡単になります (ビューモデルの中心を更新し、楕円を移動するだけです)。 .

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 Exemple}" がある場合、ViewModel で Exemple の値を変更すると、自動的に更新されます。

楕円の場合、楕円のすべてのパラメーターを含むクラスを作成し、それを ViewModel でインスタンス化し、View でバインドできます。

コマンドとイベント

上記の View の例で、Command を使用してイベントを処理する例を次に示します。もちろん、これは 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も初めてです。これは多くの方法の 1 つであり、おそらく最善の方法ではありません。何かが明確でない場合、または何かをより正確にすることができる場合は教えてください.

于 2016-07-13T10:00:41.463 に答える