私は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 つであり、おそらく最善の方法ではありません。何かが明確でない場合、または何かをより正確にすることができる場合は教えてください.