調べたところWPFで直線を引こうと思ったらXAMLでPathで静的に直線を引くことが出来るようです。
こちらを参考に、マウスのクリックイベントで直線の始点と終点を拾って、動的に直線を引く方法を考えてみました。
MVVMぽくプログラミングしようとするとPathオブジェクトを動的に生成しようとした段階で、どうすれば良いか詰んでしまいました。
自分のスキルが足りないせいだとは思いますが、とりあえずXAMLで始点や終点の情報が空のPathを用意し、C#のコード側で始点や終点の情報を追加するようにしてみました。
また、クリックした座標を拾う方法は以下の記事のコードを使わせてもらいました。
【WPF】Pathで線形を書く(直線のみ) - Qiita
#目的XAMLで適当な線形を書きたい。なのでSystem.Windows.Shapes名前空間のPathを使って書いてみる。#環境・IDE :Visual Studio 2017#方法事…
こちらを参考に、マウスのクリックイベントで直線の始点と終点を拾って、動的に直線を引く方法を考えてみました。
MVVMぽくプログラミングしようとするとPathオブジェクトを動的に生成しようとした段階で、どうすれば良いか詰んでしまいました。
自分のスキルが足りないせいだとは思いますが、とりあえずXAMLで始点や終点の情報が空のPathを用意し、C#のコード側で始点や終点の情報を追加するようにしてみました。
また、クリックした座標を拾う方法は以下の記事のコードを使わせてもらいました。
MVVM でイベント引数の値を ViewModel のコマンドに渡す方法 - かずきのBlog@hatena
こちらを見て、そういえばさらっと書いてるだけだったなぁと思ったので…。 elf-mission.net イベント引数を ViewModel で使いたい マウス系イベントや選択系イベントは、イベント引数にしか入ってない値とかもあったりして使い...
プロジェクトの作成
PowerShellで実行。要dotnet.exe
mkdir プロジェクト名
cd プロジェクト名
dotnet new wpf
dotnet add package Microsoft.Xaml.Behaviors.Wpf
dotnet add package ReactiveProperty.WPF
code .
ソースコード
ファイル名:MainWindow.xaml
<Window x:Class="DrawLine.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:DrawLine"
mc:Ignorable="d"
xmlns:i="clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors"
xmlns:interactivity="clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF"
Title="MainWindow" Height="450" Width="800">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closed">
<interactivity:EventToReactiveCommand Command="{Binding WindowClosedCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseDown">
<interactivity:EventToReactiveCommand Command="{Binding MouseDownCommand}">
<local:MouseDownToMousePositionConverter />
</interactivity:EventToReactiveCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Path Stroke="Red" StrokeThickness="1" Data="{Binding Points.Value}"/>
</Grid>
</Window>
ファイル名:MainWindowViewModel.cs
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using System.ComponentModel;
using System.Linq;
using System.Reactive.Linq;
using System;
using System.Reactive.Disposables;
namespace DrawLine
{
public class MainWindowViewModel : INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string name) =>
PropertyChanged(this, new PropertyChangedEventArgs(name));
private CompositeDisposable Disposable { get; } = new ();
public ReactiveCommand<MousePosition> MouseDownCommand { get; }
public ReadOnlyReactivePropertySlim<string> Message { get; }
public void Dispose() => Disposable.Dispose();
public ReactiveCommand<EventArgs> WindowClosedCommand { get; }
public ReactiveProperty<string> Points { get; private set; }
public MainWindowViewModel()
{
PropertyChanged += (o, e) => {};
WindowClosedCommand = new ReactiveCommand<EventArgs>()
.WithSubscribe(e =>this.Dispose()).AddTo(Disposable);
LinePair lp = new();
MouseDownCommand = new ReactiveCommand<MousePosition>()
.WithSubscribe(e =>
{
if (lp.Start.X == -1)
{
lp.SetStart(e);
}
else
{
lp.SetEnd(e);
Points.Value = lp.ToStr();
}
}).AddTo(Disposable);
Points = new ReactiveProperty<string>("").AddTo(Disposable);
}
}//class
}//ns
ファイル名:MousePosition.cs
namespace DrawLine
{
public class MousePosition
{
public double X { get; set; } = -1;
public double Y { get; set; } = -1;
}
}
ファイル名:MouseDownToMousePositionConverter.cs
using Reactive.Bindings.Interactivity;
using System;
using System.Linq;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Input;
namespace DrawLine
{
public class MouseDownToMousePositionConverter : ReactiveConverter<MouseButtonEventArgs, MousePosition>
{
protected override IObservable<MousePosition> OnConvert(IObservable<MouseButtonEventArgs> source) => source
.Where(x => x.LeftButton == MouseButtonState.Pressed)
.Select(x => x.GetPosition((IInputElement)AssociateObject))
.Select(x => new MousePosition
{
X = x.X,
Y = x.Y,
});
}
}//ns
ファイル名:LinePair.cs
namespace DrawLine
{
class LinePair
{
public MousePosition Start {get; set;} = new MousePosition();
public MousePosition End {get; set;} = new MousePosition();
public void SetStart(MousePosition x)
{
Start.X = x.X;
Start.Y = x.Y;
}
public void SetEnd(MousePosition x)
{
End.X = x.X;
End.Y = x.Y;
}
public string ToStr()
{
return string.Format("M{0},{1} L{2},{3} ", Start.X, Start.Y, End.X, End.Y);
}
}
}
マウスクリックの1回目で直線の始点、2回目以降が終点として直線が引けました。
コメント