質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
.NET

.NETとは、主に.NET Frameworkと呼ばれるアプリケーションまたは開発環境を指します。CLR(共通言語ランタイム)を搭載し、入力された言語をCIL(共通中間言語)に変換・実行することが可能です。そのため、C#やPythonなど複数の言語を用いることができます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

4回答

1390閲覧

WPF C# Rectangleを変数に入れ、今選択しているものの拡縮を実装したい

nodoita

総合スコア6

.NET

.NETとは、主に.NET Frameworkと呼ばれるアプリケーションまたは開発環境を指します。CLR(共通言語ランタイム)を搭載し、入力された言語をCIL(共通中間言語)に変換・実行することが可能です。そのため、C#やPythonなど複数の言語を用いることができます。

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2023/06/19 07:45

編集2023/06/20 05:00

お世話になります。
調べたのですが、分からないため教えてください。

実現したいこと

【WPF】Excel 図形 みたいなのを作る
https://noitalog.tokyo/wpf-excel-shape/

上記のようにドラッグで四角形を動的に作成し、
作成済の四角形をクリックすると移動したり拡縮したりしたいです。

.NET6.0/C#10.0でオートシェイプ風図形描画ライブラリを作ろう!(Chapter5)
https://qiita.com/pierusan2010/items/531199fbff10477f3064

一番作ってみたいのは、上記のオートシェイプ描画です。

ライブラリとか色々と複雑になると分からないため、
・四角形のみ(Canvas上に作成する) →ソースコピペで出来ている〇
・ドラッグで四角形を動的生成できる →ソースコピペで出来ている〇
・動的生成した四角形をドラッグ移動したり拡縮ができる →できてない×
・ドラッグ時に画面表示の為だけに使ったRectangleは不要なので削除したい→できてない×
・動的生成した四角形を選択すると、四角形の変数とか値(X,Y,Width,Height…)の値を取得できる →できていない×

上記が実行したい内容です。
できていない×の所を出来るようにしたいです。

前提

【WPF】Excel 図形 みたいなのを作る
https://noitalog.tokyo/wpf-excel-shape/

上記のソースをお借りしております。

該当のソースコード

MyRect.cs

1 public class MyRect 2 { 3 public double X { get; set; } 4 public double Y { get; set; } 5 public double Width { get; set; } 6 public double Height { get; set; } 7 public Brush Stroke { get; set; } 8 public Brush Fill { get; set; } 9 10 public MyRect(double x, double y,double width ,double height,Brush stroke,Brush fill) 11 { 12 X = x; 13 Y = y; 14 Width = width; 15 Height = height; 16 Stroke = stroke; 17 Fill = fill; 18 19 } 20 }

MainWindow.xaml.cs

1 public partial class MainWindow : Window 2 { 3 bool isMouseDown = false; 4 Point StartPoint; 5 Point MovePoint; 6 Rectangle rectangle; 7 8 public ObservableCollection<MyRect> MyRects = new ObservableCollection<MyRect>(); 9 public MainWindow() 10 { 11 InitializeComponent(); 12 13 } 14 15 private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 16 { 17 var point = e.GetPosition(MyCanvas); 18 19 //var leftOffset = point.X % 10;//罫線に合わせる必要はないためコメントアウト 20 //leftOffset = leftOffset < 5 ? -leftOffset : 10 - leftOffset; 21 //var topOffset = point.Y % 10; 22 //topOffset = topOffset < 5 ? -topOffset : 10 - topOffset; 23 var leftOffset = point.X; 24 var topOffset = point.Y; 25 26 StartPoint = new Point(point.X + leftOffset, point.Y + topOffset); 27 28 rectangle = new Rectangle 29 { 30 Stroke = Brushes.Black, 31 Fill = Brushes.LightBlue, 32 HorizontalAlignment = HorizontalAlignment.Left, 33 VerticalAlignment = VerticalAlignment.Top, 34 Width = 0, 35 Height = 0, 36 Opacity = 0.3 37 }; 38 39 Canvas.SetLeft(rectangle, StartPoint.X); 40 Canvas.SetTop(rectangle, StartPoint.Y); 41 MyCanvas.Children.Add(rectangle); 42 43 isMouseDown = true; 44 } 45 46 private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 47 { 48 var R_X = MovePoint.X; 49 var R_Y = MovePoint.Y; 50 var R_H=rectangle.ActualHeight; 51 var R_W=rectangle.ActualWidth; 52 MyRects.Add(new MyRect(R_X,R_Y,R_H,R_W, Brushes.Red, Brushes.Transparent));//追加した 53 MyCanvas.Children.Add(MyRects[MyRects.Count-1]); 54 isMouseDown = false; 55 rectangle.Opacity = 1; 56 } 57 58 private void MyCanvas_MouseMove(object sender, MouseEventArgs e) 59 { 60 if (!isMouseDown) return; 61 62 var point = e.GetPosition(MyCanvas); 63 64 //var leftOffset = point.X % 10;//罫線に合わせる必要はないためコメントアウト 65 //leftOffset = leftOffset < 5 ? -leftOffset : 10 - leftOffset; 66 //var topOffset = point.Y % 10; 67 //topOffset = topOffset < 5 ? -topOffset : 10 - topOffset; 68 69 var leftOffset = point.X; 70 var topOffset = point.Y; 71 72 MovePoint = new Point(point.X + leftOffset, point.Y + topOffset); 73 rectangle.Width = Math.Abs(MovePoint.X - StartPoint.X); 74 rectangle.Height = Math.Abs(MovePoint.Y - StartPoint.Y); 75 76 if (MovePoint.X - StartPoint.X <= 0) 77 { 78 Canvas.SetLeft(rectangle, MovePoint.X); 79 } 80 if (MovePoint.Y - StartPoint.Y <= 0) 81 { 82 Canvas.SetTop(rectangle, MovePoint.Y); 83 } 84 } 85 86 private void MyCanvas_MouseLeave(object sender, MouseEventArgs e) 87 { 88 89 } 90 }

試したこと(6/20 9:30修正)

Canvasコントロールの子要素を動的に増減させたい
https://teratail.com/questions/359699

とりあえず、Rectangleの値を動的に生成したり、
選択したRectangleのサイズ等を取得したいです。
(移動や拡縮は、おいおいやります)

とりあえず勉強の為、別で1つ作りました。

Rect.cs

1 public class MyRect 2 { 3 public double X { get; set; } 4 public double Y { get; set; } 5 public double Width { get; set; } 6 public double Height { get; set; } 7 8 } 9 10 public class RectangleItem : MyRect 11 { 12 public Brush Stroke { get; set; } 13 public Brush Fill { get; set; } 14 } 15 16 17}

xaml.cs

1 2 public MainWindow() 3 { 4 InitializeComponent(); 5 var imageFolder = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "image"); 6 DataContext = new ViewModel(imageFolder); 7 } 8 9 private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 10 { 11 var point = e.GetPosition(MyCanvas); 12 13 var leftOffset = point.X % 10; 14 leftOffset = leftOffset < 5 ? -leftOffset : 10 - leftOffset; 15 var topOffset = point.Y % 10; 16 topOffset = topOffset < 5 ? -topOffset : 10 - topOffset; 17 18 StartPoint = new Point(point.X + leftOffset, point.Y + topOffset); 19 20 rectangle = new Rectangle 21 { 22 Stroke = Brushes.Black, 23 Fill = Brushes.LightBlue, 24 HorizontalAlignment = HorizontalAlignment.Left, 25 VerticalAlignment = VerticalAlignment.Top, 26 Width = 0, 27 Height = 0, 28 Opacity = 0.3 29 }; 30 31 Canvas.SetLeft(rectangle, StartPoint.X); 32 Canvas.SetTop(rectangle, StartPoint.Y); 33 MyCanvas.Children.Add(rectangle); 34 35 isMouseDown = true; 36 } 37 38 private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 39 { 40 var R_X = MovePoint.X; 41 var R_Y = MovePoint.Y; 42 var R_H=rectangle.ActualHeight; 43 var R_W=rectangle.ActualWidth; 44 MyCanvas.Children.Remove(rectangle); 45 MyRects.Add(new RectangleItem { X = R_X, Y = R_Y, Width =R_W, Height =R_H, Fill = Brushes.Transparent, Stroke=Brushes.Red}); 46 47 48 isMouseDown = false; 49 rectangle.Opacity = 1; 50 }

MainWindow.xaml

1 <Window.Resources> 2 <DataTemplate DataType="{x:Type local:RectangleItem}"> 3 <Rectangle Width="{Binding Width}" Height="{Binding Height}" Fill="{Binding Fill}" Stroke="{Binding Stroke}" /> 4 </DataTemplate> 5 </Window.Resources> 6 <Grid> 7 <ItemsControl ItemsSource="{Binding MyRects}"> 8 <ItemsControl.ItemsPanel> 9 <ItemsPanelTemplate> 10 <Canvas /> 11 </ItemsPanelTemplate> 12 </ItemsControl.ItemsPanel> 13 <ItemsControl.ItemContainerStyle> 14 <Style> 15 <Setter Property="Canvas.Left" Value="{Binding X}" /> 16 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 17 </Style> 18 </ItemsControl.ItemContainerStyle> 19 </ItemsControl> 20 </Grid>

MyRect.cs

1 public class MyRect 2 { 3 public double X { get; set; } 4 public double Y { get; set; } 5 public double Width { get; set; } 6 public double Height { get; set; } 7 8 } 9 10 public class RectangleItem : MyRect 11 { 12 public Brush Stroke { get; set; } = Brushes.Red; 13 public Brush Fill { get; set; } = Brushes.Transparent; 14 }

MyCanvas.Children.Remove(rectangle);で
描画していた四角形を消すところまでは出来ましたが、
Rectangleが動的生成されません。なぜでしょう……?

①ViewModel.csにRectsを追加しなければならないのか?
②MyRectsの値を見るとちゃんと値は入っているものの
Rectangleが自動生成されない
→やはりViewModel.csに追加していないから?

((ViewModel)DataContext).MyRects.Add(new RectangleItem { X = 100, Y = 50, Width = 50, Height = 50 });
LeftButtonup時に上記内容を追加するようにしたら
MyRectsに値は追加されましたが四角形は表示されませんでした。

補足情報(FW/ツールのバージョンなど)

Visualstudio2022 V17.6.3
.NET 6.0 C#

TN8001👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2023/06/19 12:51 編集

> 一番作ってみたいのは、上記のオートシェイプ描画です。 もしすべてを実装したいと考えてるなら、落としてきてゆっくり解読するのが結局早いと思います。 とりあえずということなら... 「ドラッグ移動」は、比較的楽に実装する手段があります。 [C#:wpf 三角形のボタンを作成して、マウスドラッグによって動かしたい](https://teratail.com/questions/304033) [C#、WPF、MVVM形式、で画面に図形を表示したい](https://teratail.com/questions/349407) [WPF C# 親ウィンドウと子ウィンドウのデータ共有](https://teratail.com/questions/jru5bj6b9xz7g1) MouseDragElementBehaviorは、Microsoft.Xaml.Behaviors.Wpfに入っています。 「拡縮ができる」が、かなり難易度が高いです。 参考サイト1をちょっといじった程度では実現は難しいです。 InkCanvasを使ってコントロールを、(何もしなくても)移動・リサイズできちゃう裏技?があります(ただしちょっと移動しずらい^^; [C# wpf InkCanvasで四角、丸を描写後に消しゴムで消したい](https://teratail.com/questions/372920)
guest

回答4

0

InkCanvasを使うパターン

  • 生成
  • 選択
  • 移動(△不満)
  • 拡縮
  • 削除
  • 値の取得設定

全面で移動できりゃあ文句ないんだけどなぁ。

xml

1<Window 2 x:Class="Qbbt1vqknu0pgeu.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Qbbt1vqknu0pgeu" 6 xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" 7 Width="800" 8 Height="450"> 9 <Grid> 10 <Grid.ColumnDefinitions> 11 <ColumnDefinition /> 12 <ColumnDefinition Width="5" /> 13 <ColumnDefinition Width="300" /> 14 </Grid.ColumnDefinitions> 15 16 <InkCanvas 17 x:Name="inkCanvas" 18 Background="Transparent" 19 EditingMode="None" 20 MouseLeftButtonDown="InkCanvas_MouseLeftButtonDown" 21 MouseLeftButtonUp="InkCanvas_MouseLeftButtonUp" 22 MouseMove="InkCanvas_MouseMove" 23 SelectionChanged="InkCanvas_SelectionChanged" /> 24 25 <UniformGrid 26 HorizontalAlignment="Left" 27 VerticalAlignment="Top" 28 Rows="1"> 29 <UniformGrid.Resources> 30 <Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="RadioButton"> 31 <EventSetter Event="Checked" Handler="RadioButton_Checked" /> 32 </Style> 33 </UniformGrid.Resources> 34 <RadioButton Content="{x:Static local:MyInkMode.Rect}" IsChecked="True" /> 35 <RadioButton Content="{x:Static local:MyInkMode.Select}" /> 36 </UniformGrid> 37 38 <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> 39 40 <xctk:PropertyGrid 41 x:Name="propertyGrid" 42 Grid.Column="2" 43 IsCategorized="False" 44 ShowSearchBox="False" 45 ShowSortOptions="False" 46 ShowSummary="False" 47 ShowTitle="False" /> 48 </Grid> 49</Window>

cs

1using System; 2using System.Linq; 3using System.Windows; 4using System.Windows.Controls; 5using System.Windows.Input; 6using System.Windows.Media; 7using System.Windows.Shapes; 8 9namespace Qbbt1vqknu0pgeu; 10 11 12// PropertyGridに直でRectangleを渡すと、プロパティが多すぎ・編集しにくいものがあるためラップ 13public class RectangleWrapper 14{ 15 public double X { get => InkCanvas.GetLeft(rectangle); set => InkCanvas.SetLeft(rectangle, value); } 16 public double Y { get => InkCanvas.GetTop(rectangle); set => InkCanvas.SetTop(rectangle, value); } 17 public double Width { get => rectangle.Width; set => rectangle.Width = value; } 18 public double Height { get => rectangle.Height; set => rectangle.Height = value; } 19 public Color Stroke { get => ((SolidColorBrush)rectangle.Stroke).Color; set => ((SolidColorBrush)rectangle.Stroke).Color = value; } 20 public Color Fill { get => ((SolidColorBrush)rectangle.Fill).Color; set => ((SolidColorBrush)rectangle.Fill).Color = value; } 21 22 private readonly Rectangle rectangle; 23 24 public RectangleWrapper(Rectangle rectangle) => this.rectangle = rectangle; 25} 26 27public enum MyInkMode { Rect, Select, }; 28 29public partial class MainWindow : Window 30{ 31 private Point startPoint; 32 private Rectangle? rectangle; 33 34 public MainWindow() => InitializeComponent(); 35 36 private void InkCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 37 { 38 startPoint = e.GetPosition(inkCanvas); 39 40 rectangle = new Rectangle 41 { 42 Stroke = new SolidColorBrush(Colors.Black), 43 Fill = new SolidColorBrush(Colors.LightBlue), 44 Opacity = 0.3, 45 ContextMenu = new() { Items = { new MenuItem { Command = ApplicationCommands.Delete, } }, }, 46 }; 47 48 rectangle.CaptureMouse(); 49 50 inkCanvas.Children.Add(rectangle); 51 InkCanvas.SetLeft(rectangle, startPoint.X); 52 InkCanvas.SetTop(rectangle, startPoint.Y); 53 54 e.Handled = true; 55 } 56 private void InkCanvas_MouseMove(object sender, MouseEventArgs e) 57 { 58 if (rectangle == null) return; 59 60 var movePoint = e.GetPosition(inkCanvas); 61 62 rectangle.Width = Math.Abs(movePoint.X - startPoint.X); 63 rectangle.Height = Math.Abs(movePoint.Y - startPoint.Y); 64 65 if (movePoint.X - startPoint.X <= 0) InkCanvas.SetLeft(rectangle, movePoint.X); 66 if (movePoint.Y - startPoint.Y <= 0) InkCanvas.SetTop(rectangle, movePoint.Y); 67 68 e.Handled = true; 69 } 70 private void InkCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 71 { 72 if (rectangle == null) return; 73 74 rectangle.ReleaseMouseCapture(); 75 rectangle!.Opacity = 1; 76 rectangle = null; 77 78 e.Handled = true; 79 } 80 81 private void RadioButton_Checked(object sender, RoutedEventArgs e) 82 { 83 if (sender is RadioButton { Content: MyInkMode mode }) 84 { 85 inkCanvas.EditingMode = mode switch 86 { 87 MyInkMode.Rect => InkCanvasEditingMode.None, 88 MyInkMode.Select => InkCanvasEditingMode.Select, 89 _ => throw new InvalidOperationException(), 90 }; 91 } 92 } 93 94 private void InkCanvas_SelectionChanged(object sender, EventArgs e) 95 { 96 if (inkCanvas.GetSelectedElements().FirstOrDefault() is Rectangle r) 97 propertyGrid.SelectedObject = new RectangleWrapper(r); 98 else 99 propertyGrid.SelectedObject = null; 100 } 101}

アプリ画像

値の表示・変更を手抜きするため、こちらのPropertyGridを使用しています。
NuGet Gallery | Extended.Wpf.Toolkit 4.5.0

投稿2023/06/20 11:33

TN8001

総合スコア9410

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

バインドするパターン

とりあえず、Rectangleの値を動的に生成したり、選択したRectangleのサイズ等を取得したいです。(移動や拡縮は、おいおいやります)

「とりあえず」の状態で中途半端にバインドするのはあまりお勧めしませんが、もしやるならこんな感じです。
xamlが増えた割にコードビハインドも(ドラッグ関連は仕方ないのだが)もりもりで、「実際どうなの?」って気はします^^;

  • 生成
  • 選択
  • 移動
  • 拡縮
  • 削除
  • 値の取得設定

面倒なのでゴースト?(ドラッグ中の仮の四角)も、ObservableCollectionに常に含まれます(本来はAdornerで実装するのが筋)

xml

1<Window 2 x:Class="Qbbt1vqknu0pgeu.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Qbbt1vqknu0pgeu" 6 xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" 7 Width="800" 8 Height="450"> 9 <Window.Resources> 10 <DataTemplate DataType="{x:Type local:RectItem}"> 11 <Rectangle 12 Width="{Binding Width}" 13 Height="{Binding Height}" 14 Opacity="{Binding Opacity}"> 15 <Rectangle.Stroke> 16 <SolidColorBrush Color="{Binding Stroke}" /> 17 </Rectangle.Stroke> 18 <Rectangle.Fill> 19 <SolidColorBrush Color="{Binding Fill}" /> 20 </Rectangle.Fill> 21 </Rectangle> 22 </DataTemplate> 23 </Window.Resources> 24 <Grid> 25 <Grid.ColumnDefinitions> 26 <ColumnDefinition /> 27 <ColumnDefinition Width="5" /> 28 <ColumnDefinition Width="300" /> 29 </Grid.ColumnDefinitions> 30 31 <ListBox x:Name="listBox" ItemsSource="{Binding RectItems}"> 32 <ListBox.CommandBindings> 33 <CommandBinding Command="ApplicationCommands.Delete" Executed="Delete_Executed" /> 34 </ListBox.CommandBindings> 35 36 <ListBox.ItemsPanel> 37 <ItemsPanelTemplate> 38 <Canvas 39 Background="Transparent" 40 MouseLeftButtonDown="Canvas_MouseLeftButtonDown" 41 MouseLeftButtonUp="Canvas_MouseLeftButtonUp" 42 MouseMove="Canvas_MouseMove" /> 43 </ItemsPanelTemplate> 44 </ListBox.ItemsPanel> 45 <ListBox.ItemContainerStyle> 46 <Style TargetType="ListBoxItem"> 47 <Setter Property="Canvas.Left" Value="{Binding X}" /> 48 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 49 <Setter Property="Padding" Value="0" /> 50 <Setter Property="Cursor" Value="SizeAll" /> 51 <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListBoxItem_PreviewMouseLeftButtonDown" /> 52 <EventSetter Event="MouseMove" Handler="ListBoxItem_MouseMove" /> 53 <EventSetter Event="MouseLeftButtonUp" Handler="ListBoxItem_MouseLeftButtonUp" /> 54 <Setter Property="ContextMenu"> 55 <Setter.Value> 56 <ContextMenu> 57 <MenuItem Command="ApplicationCommands.Delete" /> 58 </ContextMenu> 59 </Setter.Value> 60 </Setter> 61 </Style> 62 </ListBox.ItemContainerStyle> 63 </ListBox> 64 65 <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> 66 67 <xctk:PropertyGrid 68 Grid.Column="2" 69 IsCategorized="False" 70 SelectedObject="{Binding SelectedItem, ElementName=listBox}" 71 ShowSearchBox="False" 72 ShowSortOptions="False" 73 ShowSummary="False" 74 ShowTitle="False" /> 75 </Grid> 76</Window>

cs

1using System; 2using System.Collections.ObjectModel; 3using System.ComponentModel; 4using System.Windows; 5using System.Windows.Controls; 6using System.Windows.Input; 7using System.Windows.Media; 8using CommunityToolkit.Mvvm.ComponentModel; 9 10namespace Qbbt1vqknu0pgeu; 11 12 13// 値の変更をViewに反映させるため、INotifyPropertyChanged(変更通知)を実装 14public partial class RectItem : ObservableObject 15{ 16 [ObservableProperty] private double x; 17 [ObservableProperty] private double y; 18 [ObservableProperty] private double width; 19 [ObservableProperty] private double height; 20 [ObservableProperty] private Color stroke; 21 [ObservableProperty] private Color fill; 22 [property: Browsable(false)] 23 [ObservableProperty] private double opacity = 1; 24} 25 26public partial class MainWindow : Window 27{ 28 public ObservableCollection<RectItem> RectItems { get; } = new(); 29 30 private readonly RectItem ghost; 31 private Point startPoint; 32 private bool isGhostDragging; 33 private bool isItemDragging; 34 35 public MainWindow() 36 { 37 InitializeComponent(); 38 DataContext = this; 39 40 ghost = new() { Stroke = Colors.Black, Fill = Colors.LightBlue, Opacity = 0, }; 41 RectItems.Add(ghost); 42 } 43 44 private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 45 { 46 if (sender is Canvas canvas) 47 { 48 listBox.SelectedItem = null; 49 50 canvas.CaptureMouse(); 51 isGhostDragging = true; 52 53 startPoint = e.GetPosition(canvas); 54 ghost.Opacity = 0.3; 55 ghost.X = startPoint.X; 56 ghost.Y = startPoint.Y; 57 58 e.Handled = true; 59 } 60 } 61 private void Canvas_MouseMove(object sender, MouseEventArgs e) 62 { 63 if (!isGhostDragging) return; 64 65 var movePoint = e.GetPosition((IInputElement)sender); 66 ghost.Width = Math.Abs(movePoint.X - startPoint.X); 67 ghost.Height = Math.Abs(movePoint.Y - startPoint.Y); 68 69 if (movePoint.X - startPoint.X <= 0) ghost.X = movePoint.X; 70 if (movePoint.Y - startPoint.Y <= 0) ghost.Y = movePoint.Y; 71 72 e.Handled = true; 73 } 74 private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 75 { 76 ((UIElement)sender).ReleaseMouseCapture(); 77 isGhostDragging = false; 78 79 if (2 < ghost.Width && 2 < ghost.Height) // 小さすぎると選択できないので 80 { 81 RectItems.Add(new() 82 { 83 X = ghost.X, 84 Y = ghost.Y, 85 Width = ghost.Width, 86 Height = ghost.Height, 87 Fill = Colors.Transparent, 88 Stroke = Colors.Red, 89 }); 90 } 91 92 ghost.Opacity = 0; 93 ghost.Width = 0; 94 ghost.Height = 0; 95 96 e.Handled = true; 97 } 98 99 private void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 100 { 101 if (sender is ListBoxItem listBoxItem) 102 { 103 listBoxItem.CaptureMouse(); 104 isItemDragging = true; 105 106 startPoint = e.GetPosition(listBoxItem); 107 108 listBoxItem.IsSelected = true; 109 listBoxItem.Focus(); 110 111 e.Handled = true; 112 } 113 } 114 private void ListBoxItem_MouseMove(object sender, MouseEventArgs e) 115 { 116 if (!isItemDragging) return; 117 118 if (sender is ListBoxItem { DataContext: RectItem rect } listBoxItem) 119 { 120 var canvas = VisualTreeHelper.GetParent(listBoxItem); // びみょいw 121 var movePoint = e.GetPosition((IInputElement)canvas); 122 123 rect.X = movePoint.X - startPoint.X; 124 rect.Y = movePoint.Y - startPoint.Y; 125 126 e.Handled = true; 127 } 128 } 129 private void ListBoxItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 130 { 131 if (sender is ListBoxItem listBoxItem) 132 { 133 listBoxItem.ReleaseMouseCapture(); 134 isItemDragging = false; 135 136 e.Handled = true; 137 } 138 } 139 140 private void Delete_Executed(object sender, ExecutedRoutedEventArgs e) 141 { 142 if (sender is ListBox { SelectedItem: RectItem rect }) 143 RectItems.Remove(rect); 144 } 145}

アプリ画像

INotifyPropertyChanged(変更通知)実装に、こちらを使用しています。
NuGet Gallery | CommunityToolkit.Mvvm 8.2.0
ObservableProperty 属性 - .NET Community Toolkit | Microsoft Learn

値の表示・変更を手抜きするため、こちらのPropertyGridを使用しています。
NuGet Gallery | Extended.Wpf.Toolkit 4.5.0

投稿2023/06/20 11:32

TN8001

総合スコア9410

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

とりあえず、Rectangleの値を動的に生成したり、
選択したRectangleのサイズ等を取得したいです。

いわゆる「ラバーバンド」のみです(移動リサイズは後日)

まっとうなAdornerでの実装です。Behaviorでアタッチするだけなので非常に使いやすくなっています。
その代わりカスタマイズ性はありません。直接コードを変更してください^^;

MainWindow

xml

1<Window 2 x:Class="Qt6uox4f1iujybm.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:i="http://schemas.microsoft.com/xaml/behaviors" 6 xmlns:local="clr-namespace:Qt6uox4f1iujybm" 7 Title="MainWindow" 8 Width="1000" 9 Height="800"> 10 <DockPanel> 11 <ToolBar DockPanel.Dock="Top"> 12 <Button MinWidth="128" Click="OpenRectListWindow_Click" Content="四角の詳細" /> 13 </ToolBar> 14 <Grid> 15 16 <ListBox Background="{x:Null}" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Rect.Items}"> 17 <ListBox.Resources> 18 <DataTemplate DataType="{x:Type local:RectItem}"> 19 <Rectangle Width="{Binding Width, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}" Fill="{Binding Fill}" Stroke="{Binding Stroke}" StrokeThickness="{Binding StrokeThickness}" /> 20 </DataTemplate> 21 </ListBox.Resources> 22 23 <ListBox.ItemsPanel> 24 <ItemsPanelTemplate> 25 <Canvas> 26 <i:Interaction.Behaviors> 27 <local:RubberBandBehavior NewRect="RubberBandBehavior_NewRect" /> 28 </i:Interaction.Behaviors> 29 </Canvas> 30 </ItemsPanelTemplate> 31 </ListBox.ItemsPanel> 32 <ListBox.ItemContainerStyle> 33 <Style TargetType="ListBoxItem"> 34 <Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay}" /> 35 <Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay}" /> 36 <Setter Property="Template"> 37 <Setter.Value> 38 <ControlTemplate TargetType="ListBoxItem"> 39 <Grid> 40 <Rectangle x:Name="rectangle" Margin="-4" Stroke="Black" StrokeDashArray="4 4" Visibility="Collapsed" /> 41 <ContentPresenter /> 42 </Grid> 43 <ControlTemplate.Triggers> 44 <Trigger Property="IsSelected" Value="True"> 45 <Setter TargetName="rectangle" Property="Visibility" Value="Visible" /> 46 </Trigger> 47 </ControlTemplate.Triggers> 48 </ControlTemplate> 49 </Setter.Value> 50 </Setter> 51 <Style.Triggers> 52 <DataTrigger Binding="{Binding}" Value="{x:Static CollectionView.NewItemPlaceholder}"> 53 <Setter Property="Visibility" Value="Collapsed" /> 54 </DataTrigger> 55 </Style.Triggers> 56 </Style> 57 </ListBox.ItemContainerStyle> 58 </ListBox> 59 </Grid> 60 </DockPanel> 61</Window>

cs

1using System.Windows; 2 3namespace Qt6uox4f1iujybm; 4 5 6public partial class MainWindow : Window 7{ 8 private ViewModel Vm => (ViewModel)DataContext; 9 10 public MainWindow() 11 { 12 InitializeComponent(); 13 DataContext = new ViewModel { Rect = new(), }; 14 } 15 16 private void OpenRectListWindow_Click(object sender, RoutedEventArgs e) => new RectListWindow { DataContext = Vm.Rect, Owner = this, }.Show(); 17 18 private void RubberBandBehavior_NewRect(object sender, NewRectEventArgs e) => Vm.Rect?.AddItem(e.Rect); 19}

RectListWindow

xml

1<Window 2 x:Class="Qt6uox4f1iujybm.RectListWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Title="四角の詳細" Width="800" Height="300"> 6 <Grid> 7 <DataGrid AutoGenerateColumns="False" ColumnWidth="*" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Items}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"> 8 <DataGrid.Columns> 9 <DataGridTextColumn Binding="{Binding X}" Header="X" /> 10 <DataGridTextColumn Binding="{Binding Y}" Header="Y" /> 11 <DataGridTextColumn Binding="{Binding Width}" Header="Width" /> 12 <DataGridTextColumn Binding="{Binding Height}" Header="Height" /> 13 <DataGridTextColumn Binding="{Binding StrokeThickness}" Header="StrokeThickness" /> 14 <DataGridTemplateColumn Width="Auto"> 15 <DataGridTemplateColumn.CellTemplate> 16 <DataTemplate> 17 <Button x:Name="button" Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding}" Content="削除" /> 18 <DataTemplate.Triggers> 19 <DataTrigger Binding="{Binding Item, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridRow}}" Value="{x:Static CollectionView.NewItemPlaceholder}"> 20 <Setter TargetName="button" Property="IsEnabled" Value="False" /> 21 </DataTrigger> 22 </DataTemplate.Triggers> 23 </DataTemplate> 24 </DataGridTemplateColumn.CellTemplate> 25 </DataGridTemplateColumn> 26 </DataGrid.Columns> 27 </DataGrid> 28 </Grid> 29</Window>

RubberBandBehavior

cs

1using System.Windows; 2using System.Windows.Controls; 3using System.Windows.Documents; 4using System.Windows.Input; 5using System.Windows.Media; 6using Microsoft.Xaml.Behaviors; 7 8namespace Qt6uox4f1iujybm; 9 10 11public class RubberBandBehavior : Behavior<Canvas> 12{ 13 public event NewRectEventHandler? NewRect; 14 15 private RubberBandAdorner adorner = null!; 16 private bool isMouseDown; 17 18 protected override void OnAttached() 19 { 20 AssociatedObject.Loaded += Loaded; 21 AssociatedObject.MouseLeftButtonDown += MouseLeftButtonDown; 22 AssociatedObject.MouseMove += MouseMove; 23 AssociatedObject.MouseLeftButtonUp += MouseLeftButtonUp; 24 } 25 protected override void OnDetaching() 26 { 27 AssociatedObject.Loaded -= Loaded; 28 AssociatedObject.MouseLeftButtonDown -= MouseLeftButtonDown; 29 AssociatedObject.MouseMove -= MouseMove; 30 AssociatedObject.MouseLeftButtonUp -= MouseLeftButtonUp; 31 32 AdornerLayer.GetAdornerLayer(AssociatedObject)?.Remove(adorner); 33 } 34 35 private void Loaded(object sender, RoutedEventArgs e) 36 { 37 adorner = new RubberBandAdorner(AssociatedObject); 38 AdornerLayer.GetAdornerLayer(AssociatedObject).Add(adorner); 39 40 if (AssociatedObject.Background == null) 41 AssociatedObject.Background = Brushes.Transparent; 42 } 43 44 private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 45 { 46 AssociatedObject.CaptureMouse(); 47 48 var p = e.GetPosition(AssociatedObject); 49 adorner.StartPoint = adorner.EndPoint = p; 50 51 isMouseDown = true; 52 } 53 private void MouseMove(object sender, MouseEventArgs e) 54 { 55 if (isMouseDown) adorner.EndPoint = e.GetPosition(AssociatedObject); 56 } 57 private void MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 58 { 59 if (isMouseDown) 60 { 61 AssociatedObject.ReleaseMouseCapture(); 62 isMouseDown = false; 63 64 var args = new NewRectEventArgs(this) 65 { 66 Rect = new(adorner.StartPoint, adorner.EndPoint), 67 RoutedEvent = RubberBandAdorner.NewRectEvent, 68 Source = AssociatedObject, 69 }; 70 NewRect?.Invoke(this, args); 71 72 adorner.StartPoint = adorner.EndPoint = default; 73 } 74 } 75 76 private class RubberBandAdorner : Adorner 77 { 78 public static readonly RoutedEvent NewRectEvent 79 = EventManager.RegisterRoutedEvent(nameof(NewRect), RoutingStrategy.Bubble, 80 typeof(NewRectEventHandler), typeof(RubberBandAdorner)); 81 82 public Point StartPoint { get => (Point)GetValue(StartPointProperty); set => SetValue(StartPointProperty, value); } 83 public static readonly DependencyProperty StartPointProperty 84 = DependencyProperty.Register(nameof(StartPoint), typeof(Point), typeof(RubberBandAdorner), 85 new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsRender)); 86 87 public Point EndPoint { get => (Point)GetValue(EndPointProperty); set => SetValue(EndPointProperty, value); } 88 public static readonly DependencyProperty EndPointProperty 89 = DependencyProperty.Register(nameof(EndPoint), typeof(Point), typeof(RubberBandAdorner), 90 new FrameworkPropertyMetadata(default(Point), FrameworkPropertyMetadataOptions.AffectsRender)); 91 92 public RubberBandAdorner(UIElement adornedElement) : base(adornedElement) { } 93 94 private readonly Pen pen = new(new SolidColorBrush(Colors.Black) { Opacity = 0.3, }, 1); 95 private readonly Brush brush = new SolidColorBrush(Colors.SkyBlue) { Opacity = 0.3, }; 96 97 protected override void OnRender(DrawingContext drawingContext) 98 => drawingContext.DrawRectangle(brush, pen, new(StartPoint, EndPoint)); 99 } 100} 101 102public class NewRectEventArgs : RoutedEventArgs 103{ 104 public Rect Rect { get; init; } 105 public NewRectEventArgs(object source) : base(null, source) { } 106} 107public delegate void NewRectEventHandler(object sender, NewRectEventArgs e);

ViewModel&Model

cs

1using CommunityToolkit.Mvvm.ComponentModel; 2using CommunityToolkit.Mvvm.Input; 3using System.Collections.ObjectModel; 4using System.Windows; 5using System.Windows.Media; 6 7namespace Qt6uox4f1iujybm; 8 9 10public partial class ViewModel 11{ 12 public RectModel? Rect { get; init; } 13} 14 15public partial class RectModel : ObservableObject 16{ 17 public ObservableCollection<RectItem> Items { get; } = new(); 18 [RelayCommand] private void Delete(RectItem item) => Items.Remove(item); 19 20 public void AddItem(Rect rect) 21 { 22 if (10 < rect.Width && 10 < rect.Height) Items.Add(new(rect)); 23 } 24} 25 26public partial class RectItem : ObservableObject 27{ 28 [ObservableProperty] private double x; 29 [ObservableProperty] private double y; 30 [ObservableProperty] private double width; 31 [ObservableProperty] private double height; 32 33 [ObservableProperty] private double strokeThickness = 3; 34 [ObservableProperty] private Brush stroke = Brushes.Red; 35 [ObservableProperty] private Brush fill = Brushes.Transparent; 36 37 public RectItem() { } 38 public RectItem(Rect rect) => (X, Y, Width, Height) = (rect.X, rect.Y, rect.Width, rect.Height); 39}

アプリ動画

投稿2023/07/12 13:55

編集2023/07/12 14:00
TN8001

総合スコア9410

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

0

自己解決

とりあえずこれで上手くいきました。
選択したRectの取得方法等は、色々調べて分からなければまた相談させてください。
TN8001様、アドバイスありがとうございました。

C#

1 var R_X = StartPoint.X; 2 var R_Y = StartPoint.Y; 3 if (MovePoint.X - StartPoint.X <= 0) 4 { 5 R_X = MovePoint.X; 6 } 7 if (MovePoint.Y - StartPoint.Y <= 0) 8 { 9 R_Y = MovePoint.Y; 10 } 11 12 var R_H = rectangle.Height; 13 var R_W = rectangle.Width; 14 MyCanvas.Children.Remove(rectangle); 15 ((ViewModel)DataContext).MyRects.Add(new RectangleItem { X = R_X, Y = R_Y, Width = R_W, Height = R_H }); 16

投稿2023/06/20 05:07

nodoita

総合スコア6

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2023/06/20 11:34

解決されたようですがコードが断片的で閲覧者の役に立たないので、完動コードをあげておきます^^
nodoita

2023/06/21 00:12

ありがとうございます!お手数をおかけしました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問