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

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

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

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

C#

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

WPF

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

Q&A

解決済

5回答

1510閲覧

WPF 動的生成したRectangleがドラッグで移動できない、Bindingが難しい…

nodoita

総合スコア6

.NET

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

C#

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

WPF

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

0グッド

0クリップ

投稿2023/06/26 07:06

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

実現したいこと

Rectangleの内容をDataGridに表示させ
今編集しようとしているRectangleの行を選択して値を動的に変更したい
作成済みのRectangleを選択すると、
選択したRectangleと同じDataGridの行が選択したい

前提

MainWindowと、SubWindow(画像選択用)、DataGridList(四角形のデータ表示用)があります。
MainWindowに四角形を描画し、その四角形を移動させたり拡縮させたりしたいです。
選択したRectの情報はActiveRectで取得できているのですが移動ができません。
とりあえず「DataGridList.xaml」を作成しました。
データをDataGridList.xamlに表示出来そうですが
Rectangleを選択したら、同じ値のDataGrid行を選択できますか?
編集中の図形「activeRect」を取得することは出来ています。

該当のソースコード

MainWindow.xaml.cs

1namespace TEST 2{ 3 public partial class MainWindow : Window 4 { 5 public MainWindow() 6 { 7 InitializeComponent(); 8 DataContext = new ViewModel(); 9 } 10 private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 11 { 12 var point = e.GetPosition(MyCanvas); 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 StartPoint = new Point(point.X + leftOffset, point.Y + topOffset); 18 rectangle = new System.Windows.Shapes.Rectangle 19 { 20 Stroke = Brushes.Black, 21 Fill = Brushes.LightBlue, 22 HorizontalAlignment = HorizontalAlignment.Left, 23 VerticalAlignment = VerticalAlignment.Top, 24 Width = 0, 25 Height = 0, 26 Opacity = 0.3, 27 }; 28 Panel.SetZIndex(rectangle, 0);//最前面表示 29 Canvas.SetLeft(rectangle, StartPoint.X); 30 Canvas.SetTop(rectangle, StartPoint.Y); 31 MyCanvas.Children.Add(rectangle); 32 isMouseDown = true; 33 } 34 private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 35 { 36 var R_X = StartPoint.X; 37 var R_Y = StartPoint.Y; 38 if (MovePoint.X - StartPoint.X <= 0) R_X = MovePoint.X; 39 if (MovePoint.Y - StartPoint.Y <= 0)R_Y = MovePoint.Y; 40 var R_H = rectangle.Height; 41 var R_W = rectangle.Width; 42 MyCanvas.Children.Remove(rectangle); 43 MyRect NowRect = new RectangleItem { X = R_X, Y = R_Y, Width = R_W, Height = R_H }; 44 ((ViewModel)DataContext).MyRects.Add(NowRect); 45 isMouseDown = false; 46 rectangle.Opacity = 1; 47 } 48 49 50 private void MyCanvas_MouseMove(object sender, MouseEventArgs e) 51 { 52if (!isMouseDown) return; 53var point = e.GetPosition(MyCanvas); 54var leftOffset = point.X % 10; 55leftOffset = leftOffset < 5 ? -leftOffset : 10 - leftOffset; 56var topOffset = point.Y % 10; 57topOffset = topOffset < 5 ? -topOffset : 10 - topOffset; 58MovePoint = new Point(point.X + leftOffset, point.Y + topOffset); 59rectangle.Width = Math.Abs(MovePoint.X - StartPoint.X); 60rectangle.Height = Math.Abs(MovePoint.Y - StartPoint.Y); 61 if (MovePoint.X - StartPoint.X <= 0)Canvas.SetLeft(rectangle, MovePoint.X); 62 if (MovePoint.Y - StartPoint.Y <= 0)Canvas.SetTop(rectangle, MovePoint.Y); 63 } 64 65private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 66 { 67 activeRect = sender as System.Windows.Shapes.Rectangle; 68 if (activeRect == null) return; 69 if (e.LeftButton != MouseButtonState.Pressed) return; 70 activeRect.Fill = Brushes.AliceBlue; 71 } 72 private void Rectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 73 { 74 Cursor = Cursors.Arrow; 75 } 76 } 77} 78

試したこと

動かすことを最優先です。
Gridが追加され、中にRectangle、LINEがあることを確認。
Rectangleクリック移動で、RectangleMoveなどのイベントが動作確認済。
ビジュアルツリーモード中にMyRectの値を変更してもRect移動なしでした。

((ViewModel)DataContext).MyRects.Add(NowRect);
だから図形が動かないのでしょうか?

図形のドラッグ移動に関する資料がそこまでないのと、
複数図形を配置してXやYなどの座標をBinding?で動かそうとしている資料があまりなく
参考になるサイト等があれば教えてください。

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

Visualstudio2022 V17.6.3
.NET 6.0 C#

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

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

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

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

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

guest

回答5

0

ベストアンサー

サンプルが欲しいとのことなので、MVVMサンプルをアップしました。

https://github.com/hqf00342/wpfBindingSample

サンプルはCanvasにコレクション管理機能を追加しBindingしていますが、その機能を持つItemsControlをCanvas化したり、ドラッグ移動にThumbコントロールを使う方がwpfらしいです。
追記:ItemsControl例としてListBox版もサンプルに追加しました。

投稿2023/06/26 17:48

編集2023/07/02 05:16
hqf00342

総合スコア273

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

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

nodoita

2023/07/04 01:19

返信が遅れて大変申し訳ありません! ありがとうございました!!すごいです!! 1つずつ勉強していきます!
guest

0

ビヘイビア化してより使い勝手をよくしました^^

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 <Window.Resources> 11 12 <!-- 13 移動・リサイズに使用するテンプレート 14 (DragDeltaイベントで動かすので)Thumbがないと何もしない 15 Alignmentを見てどこの部分か判断するので配置法に注意 16 --> 17 <ControlTemplate x:Key="ResizeAdornerTemplate"> 18 <ControlTemplate.Resources> 19 <Style TargetType="Thumb"> 20 <Setter Property="Template"> 21 <Setter.Value> 22 <ControlTemplate> 23 <Rectangle MinWidth="10" MinHeight="10" Margin="-5" Fill="Transparent" /> 24 </ControlTemplate> 25 </Setter.Value> 26 </Setter> 27 </Style> 28 </ControlTemplate.Resources> 29 <Grid> 30 31 <!-- 移動 --> 32 <Thumb Cursor="SizeAll" /> 33 34 <!-- 辺 リサイズ --> 35 <Thumb HorizontalAlignment="Left" Cursor="SizeWE" /> 36 <Thumb HorizontalAlignment="Right" Cursor="SizeWE" /> 37 <Thumb VerticalAlignment="Top" Cursor="SizeNS" /> 38 <Thumb VerticalAlignment="Bottom" Cursor="SizeNS" /> 39 40 <!-- 角 リサイズ --> 41 <Thumb HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="SizeNWSE" /> 42 <Thumb HorizontalAlignment="Right" VerticalAlignment="Top" Cursor="SizeNESW" /> 43 <Thumb HorizontalAlignment="Left" VerticalAlignment="Bottom" Cursor="SizeNESW" /> 44 <Thumb HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeNWSE" /> 45 </Grid> 46 </ControlTemplate> 47 48 <DataTemplate DataType="{x:Type local:RectItem}"> 49 <Rectangle Width="{Binding Width, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}" Fill="{Binding Fill}" Stroke="{Binding Stroke}" StrokeThickness="{Binding StrokeThickness}"> 50 <i:Interaction.Behaviors> 51 52 <!-- 53 ドラッグで移動・リサイズするビヘイビア 54 リサイズさせたいアイテム自体にアタッチ 55 ItemsPanelがCanvasのListBoxに配置されるという前提 56 --> 57 <local:ResizeBehavior AdornerTemplate="{StaticResource ResizeAdornerTemplate}" /> 58 </i:Interaction.Behaviors> 59 </Rectangle> 60 </DataTemplate> 61 </Window.Resources> 62 <DockPanel> 63 <ToolBar DockPanel.Dock="Top"> 64 <Button MinWidth="128" Click="OpenRectListWindow_Click" Content="四角の詳細" /> 65 </ToolBar> 66 <Grid> 67 <ListBox Background="{x:Null}" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Rect.Items}"> 68 <ListBox.ItemsPanel> 69 <ItemsPanelTemplate> 70 <Canvas /> 71 </ItemsPanelTemplate> 72 </ListBox.ItemsPanel> 73 <ListBox.ItemContainerStyle> 74 <Style TargetType="ListBoxItem"> 75 <Setter Property="Canvas.Left" Value="{Binding X, Mode=TwoWay}" /> 76 <Setter Property="Canvas.Top" Value="{Binding Y, Mode=TwoWay}" /> 77 <Setter Property="Template"> 78 <Setter.Value> 79 <ControlTemplate TargetType="ListBoxItem"> 80 <Grid> 81 <Rectangle x:Name="rectangle" Margin="-4" Stroke="Black" StrokeDashArray="4 4" Visibility="Collapsed" /> 82 <ContentPresenter /> 83 </Grid> 84 <ControlTemplate.Triggers> 85 <Trigger Property="IsSelected" Value="True"> 86 <Setter TargetName="rectangle" Property="Visibility" Value="Visible" /> 87 </Trigger> 88 </ControlTemplate.Triggers> 89 </ControlTemplate> 90 </Setter.Value> 91 </Setter> 92 <Style.Triggers> 93 <DataTrigger Binding="{Binding}" Value="{x:Static CollectionView.NewItemPlaceholder}"> 94 <Setter Property="Visibility" Value="Collapsed" /> 95 </DataTrigger> 96 </Style.Triggers> 97 </Style> 98 </ListBox.ItemContainerStyle> 99 </ListBox> 100 </Grid> 101 </DockPanel> 102</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) 17 => new RectListWindow { DataContext = Vm.Rect, Owner = this, }.Show(); 18}

ResizeBehavior

cs

1using System; 2using System.Windows; 3using System.Windows.Controls; 4using System.Windows.Controls.Primitives; 5using System.Windows.Documents; 6using System.Windows.Input; 7using System.Windows.Media; 8using Microsoft.Xaml.Behaviors; 9 10namespace Qt6uox4f1iujybm; 11 12 13// 動かしたい本体(例ではRectangle)にアタッチ 14// ItemsPanelがCanvasのListBoxに置かれるという前提 15public class ResizeBehavior : Behavior<FrameworkElement> 16{ 17 // Thumbが置いてあるControlTemplate 18 public ControlTemplate? AdornerTemplate { get; set; } 19 20 // ↑を実体化したControlを持つAdorner 21 private ResizeAdorner adorner = null!; 22 // アタッチ元(AssociatedObject)を包含するListBoxItem 23 private ListBoxItem listBoxItem = null!; 24 // アタッチ元(AssociatedObject)が置かれているCanvas 25 private Canvas canvas = null!; 26 27 private Point topLeft; // ドラッグ開始時の左上座標(Canvas基準) 28 private Point bottomRight; // ドラッグ開始時の右下座標(Canvas基準) 29 private Point offset; // ドラッグ開始時のクリックした座標(ListBoxItem基準) 30 31 protected override void OnAttached() => AssociatedObject.Loaded += Loaded; 32 protected override void OnDetaching() 33 { 34 AssociatedObject.Loaded -= Loaded; 35 36 listBoxItem.Selected -= ListBoxItem_Selected; 37 listBoxItem.Unselected -= ListBoxItem_Unselected; 38 39 adorner.RemoveHandler(Thumb.DragStartedEvent, (DragStartedEventHandler)Thumb_DragStarted); 40 adorner.RemoveHandler(Thumb.DragDeltaEvent, (DragDeltaEventHandler)Thumb_DragDelta); 41 } 42 43 private void Loaded(object sender, RoutedEventArgs e) 44 { 45 var container = AssociatedObject; 46 while (true) 47 { 48 var parent = VisualTreeHelper.GetParent(container) as FrameworkElement ?? throw new InvalidOperationException("Canvas not found."); 49 if (parent is Canvas c) 50 { 51 canvas = c; 52 break; 53 } 54 container = parent; 55 } 56 57 listBoxItem = container as ListBoxItem ?? throw new InvalidOperationException("ListBoxItem not found."); 58 listBoxItem.Selected += ListBoxItem_Selected; 59 listBoxItem.Unselected += ListBoxItem_Unselected; 60 61 adorner = new ResizeAdorner(AssociatedObject, AdornerTemplate); 62 // Thumbのイベントは親でまとめてハンドルする 63 adorner.AddHandler(Thumb.DragStartedEvent, (DragStartedEventHandler)Thumb_DragStarted); 64 adorner.AddHandler(Thumb.DragDeltaEvent, (DragDeltaEventHandler)Thumb_DragDelta); 65 66 if (listBoxItem.IsSelected) 67 AdornerLayer.GetAdornerLayer(AssociatedObject).Add(adorner); 68 } 69 70 71 // 選択時にAdorner追加(= 移動・リサイズ可能) 72 private void ListBoxItem_Selected(object sender, RoutedEventArgs e) 73 => AdornerLayer.GetAdornerLayer(AssociatedObject).Add(adorner); 74 // 選択解除時にAdorner削除 75 private void ListBoxItem_Unselected(object sender, RoutedEventArgs e) 76 => AdornerLayer.GetAdornerLayer(AssociatedObject)?.Remove(adorner); 77 78 private void Thumb_DragStarted(object sender, DragStartedEventArgs e) 79 { 80 // ドラッグ開始時の各点保存 81 topLeft = new Point(Canvas.GetLeft(listBoxItem), Canvas.GetTop(listBoxItem)); 82 bottomRight = topLeft + new Vector(AssociatedObject.Width, AssociatedObject.Height); 83 offset = Mouse.GetPosition(listBoxItem); 84 } 85 private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) 86 { 87 if (e.OriginalSource is Thumb thumb) 88 { 89 var p = Mouse.GetPosition(canvas); 90 91 // 移動 92 if (thumb.HorizontalAlignment == HorizontalAlignment.Stretch && thumb.VerticalAlignment == VerticalAlignment.Stretch) 93 { 94 // offset分戻して左上座標設定 95 var pp = p - offset; 96 Canvas.SetLeft(listBoxItem, pp.X); 97 Canvas.SetTop(listBoxItem, pp.Y); 98 return; 99 } 100 101 // リサイズ 102 // X(左右)について 103 // 例えばAlignment.LeftならbottomRight.Xは動かさずもう一方だけ動かせばいい 104 // 仮にbottomRight.Xより大きくなって(左辺を持って右辺より右に行く) 105 // Widthがマイナスになるとしても後で正規化するので問題ない 106 var (x1, x2) = thumb.HorizontalAlignment switch 107 { 108 HorizontalAlignment.Left => (p.X, bottomRight.X), 109 HorizontalAlignment.Right => (topLeft.X, p.X), 110 _ => (topLeft.X, bottomRight.X), 111 }; 112 // Y(上下)について 同上 113 var (y1, y2) = thumb.VerticalAlignment switch 114 { 115 VerticalAlignment.Top => (p.Y, bottomRight.Y), 116 VerticalAlignment.Bottom => (topLeft.Y, p.Y), 117 _ => (topLeft.Y, bottomRight.Y), 118 }; 119 120 // 正規化はRectがやってくれる 121 var rect = new Rect(new Point(x1, y1), new Point(x2, y2)); 122 Canvas.SetLeft(listBoxItem, rect.X); 123 Canvas.SetTop(listBoxItem, rect.Y); 124 AssociatedObject.Width = rect.Width; 125 AssociatedObject.Height = rect.Height; 126 } 127 } 128 129 // [リサイズハンドルをAdornerで実装する - CoMoの日記](https://como-2.hatenadiary.org/entry/20110428/1303996288) 130 private class ResizeAdorner : Adorner 131 { 132 private readonly Control content; 133 134 public ResizeAdorner(UIElement adornedElement, ControlTemplate? template) : base(adornedElement) 135 { 136 content = new() { Template = template, }; 137 AddVisualChild(content); 138 AddLogicalChild(content); 139 } 140 141 protected override Size MeasureOverride(Size constraint) => AdornedElement.DesiredSize; 142 protected override Size ArrangeOverride(Size finalSize) 143 { 144 content.Arrange(new Rect(AdornedElement.DesiredSize)); 145 return AdornedElement.DesiredSize; 146 } 147 protected override int VisualChildrenCount => 1; 148 protected override Visual GetVisualChild(int index) => content; 149 } 150}

ViewModel&Model

cs

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

アプリ動画

投稿2023/07/13 14:09

TN8001

総合スコア9326

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

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

guest

0

Rectangleの内容をDataGridに表示させ
今編集しようとしているRectangleの行を選択して値を動的に変更したい

図形自体を移動・拡縮できるんであれば、DataGridで表示・編集できる意味ありますか?(選択確認用?)

作成済みのRectangleを選択すると、
選択したRectangleと同じDataGridの行が選択したい

2つ前の回答では選択・移動ができています。
WPF C# Rectangleを変数に入れ、今選択しているものの拡縮を実装したい

なぜ選択できているかというと、ListBoxを使ったからです(そのかわり細かい注意点があります)
ItemsControlを使うのであれば、選択の仕組みから作らなければなりません。

MainWindowと、SubWindow(画像選択用)、DataGridList(四角形のデータ表示用)があります。

技術検証中は(作る予定のアプリとは別の)シンプルな構成で試行錯誤するのを勧めます。

ビジュアルツリーモード中にMyRectの値を変更してもRect移動なしでした。

INotifyPropertyChanged(変更通知)を実装してください。
なくても動いてしまうこともあるのですが、望ましくはありません。
ObservableCollectionの要素クラスのプロパティ

図形のドラッグ移動に関する資料がそこまでないのと、
複数図形を配置してXやYなどの座標をBinding?で動かそうとしている資料があまりなく
参考になるサイト等があれば教えてください。

これまでの回答でヒントやキーワードは十分出しているつもりなんですが、具体的に書かないと通じませんか?
具体的に出したところでそのまま使えるような形にはなっていませんが...

バインドしているかはあまり関係がありません。
双方向でバインドしていれば、Rectangleを変えればRectangleItemも変わるし逆もしかりです。

個々の課題についてアイデアや解決策を提供することはできます。
しかしあなたのアプリを代わりに作る場ではないので十分留意してください。

例えば動的追加ができているならそれはオミットし、最初から四角が入ったコレクションを用意してください(このままでは到底1万字に収まらなくなります)

xml

1<Window 2 x:Class="Qj700zzpncph60k.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:Qj700zzpncph60k" 6 Width="800" 7 Height="450"> 8 <Window.Resources> 9 <DataTemplate DataType="{x:Type local:RectangleItem}"> 10 <Rectangle 11 x:Name="rect" 12 Width="{Binding Width}" 13 Height="{Binding Height}" 14 Fill="{Binding Fill}" 15 MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" 16 MouseLeftButtonUp="Rectangle_MouseLeftButtonUp" 17 MouseMove="Rectangle_MouseMove" 18 Stroke="{Binding Stroke}" 19 StrokeThickness="{Binding StrokeThickness}" /> 20 <DataTemplate.Triggers> 21 <DataTrigger Binding="{Binding IsSelected}" Value="True"> 22 <Setter TargetName="rect" Property="Fill" Value="AliceBlue" /> 23 <Setter TargetName="rect" Property="Cursor" Value="SizeAll" /> 24 </DataTrigger> 25 </DataTemplate.Triggers> 26 </DataTemplate> 27 </Window.Resources> 28 29 <Grid> 30 <Grid.ColumnDefinitions> 31 <ColumnDefinition /> 32 <ColumnDefinition Width="5" /> 33 <ColumnDefinition Width="300" /> 34 </Grid.ColumnDefinitions> 35 36 <!-- ラバーバンド用Canvas --> 37 <Canvas 38 x:Name="MyCanvas" 39 Background="Transparent" 40 MouseLeftButtonDown="MyCanvas_MouseLeftButtonDown" 41 MouseLeftButtonUp="MyCanvas_MouseLeftButtonUp" 42 MouseMove="MyCanvas_MouseMove"> 43 <ItemsControl ItemsSource="{Binding Shapes}"> 44 <ItemsControl.ItemsPanel> 45 <ItemsPanelTemplate> 46 <!-- 図形描画用Canvas Canvasの中にCanvasが入ってる形(あんまりイケてない^^; --> 47 <Canvas /> 48 </ItemsPanelTemplate> 49 </ItemsControl.ItemsPanel> 50 <ItemsControl.ItemContainerStyle> 51 <Style> 52 <Setter Property="Canvas.Left" Value="{Binding X}" /> 53 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 54 </Style> 55 </ItemsControl.ItemContainerStyle> 56 </ItemsControl> 57 58 <!-- ラバーバンド(ゴースト)四角 --> 59 <Rectangle 60 x:Name="rectangle" 61 Fill="LightBlue" 62 Opacity="0" 63 Stroke="Black" /> 64 </Canvas> 65 66 <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" /> 67 68 <DataGrid 69 Grid.Column="2" 70 CanUserAddRows="False" 71 ItemsSource="{Binding Shapes}" 72 SelectedItem="{Binding SelectedShape}" /> 73 </Grid> 74</Window>

cs

1using System; 2using System.Collections.ObjectModel; 3using System.Windows; 4using System.Windows.Controls; 5using System.Windows.Input; 6using System.Windows.Media; 7using System.Windows.Shapes; 8using CommunityToolkit.Mvvm.ComponentModel; 9 10namespace Qj700zzpncph60k; 11 12 13// 値の変更をViewに反映させるため、INotifyPropertyChanged(変更通知)を実装 14public partial class ShapeItem : 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 bool isSelected; 21} 22public partial class RectangleItem : ShapeItem 23{ 24 [ObservableProperty] private double strokeThickness = 3; 25 [ObservableProperty] private Brush stroke = Brushes.Red; 26 [ObservableProperty] private Brush fill = Brushes.Transparent; 27} 28 29public partial class ViewModel : ObservableObject 30{ 31 public ObservableCollection<ShapeItem> Shapes { get; } = new(); 32 [ObservableProperty] private ShapeItem? selectedShape; 33} 34 35public partial class MainWindow : Window 36{ 37 private bool isMouseDown; 38 private Point startPoint; 39 private Rectangle? draggingRect; 40 41 private readonly ViewModel vm = new(); 42 43 public MainWindow() 44 { 45 InitializeComponent(); 46 DataContext = vm; 47 } 48 49 private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 50 { 51 // キャプチャしないとCanvas外でのMouseUpが取れなくなる等でバグりやすい 52 MyCanvas.CaptureMouse(); 53 54 var p = e.GetPosition(MyCanvas); 55 56 var x = (int)(p.X + 5) / 10 * 10; 57 var y = (int)(p.Y + 5) / 10 * 10; 58 startPoint = new Point(x, y); 59 60 Canvas.SetLeft(rectangle, x); 61 Canvas.SetTop(rectangle, y); 62 rectangle.Width = 0; 63 rectangle.Height = 0; 64 rectangle.Opacity = 0.3; 65 66 isMouseDown = true; 67 } 68 private void MyCanvas_MouseMove(object sender, MouseEventArgs e) 69 { 70 if (!isMouseDown) return; 71 72 var p = e.GetPosition(MyCanvas); 73 74 var x = (int)(p.X + 5) / 10 * 10; 75 var y = (int)(p.Y + 5) / 10 * 10; 76 77 //if (x < startPoint.X) Canvas.SetLeft(rectangle, x); 78 //if (y < startPoint.Y) Canvas.SetTop(rectangle, y); 79 // ↑↓同じでないことに注意 80 // MouseDownした点を中心に円を描くようにマウスを動かすとわかりやすい 81 // (もちろんわたしは)↓のほうが気持ちいいが、↑ならサイズ0の四角は描けない利点あり 82 Canvas.SetLeft(rectangle, x < startPoint.X ? x : startPoint.X); 83 Canvas.SetTop(rectangle, y < startPoint.Y ? y : startPoint.Y); 84 85 rectangle.Width = Math.Abs(x - startPoint.X); 86 rectangle.Height = Math.Abs(y - startPoint.Y); 87 } 88 private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 89 { 90 if (!isMouseDown) return; 91 92 MyCanvas.ReleaseMouseCapture(); 93 rectangle.Opacity = 0; 94 isMouseDown = false; 95 96 var x = Canvas.GetLeft(rectangle); 97 var y = Canvas.GetTop(rectangle); 98 var w = rectangle.Width; 99 var h = rectangle.Height; 100 101 if (w < 10 || h < 10) return; 102 103 ShapeItem nowRect = new RectangleItem { X = x, Y = y, Width = w, Height = h, }; 104 vm.Shapes.Add(nowRect); 105 } 106 107 // 描いた直後にはなぜか来ない!?(2回クリックすれば来る。謎い。Canvasが入れ子だからか??) 108 private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 109 { 110 if (sender is Rectangle { DataContext: ShapeItem shape } rectangle) 111 { 112 vm.SelectedShape = shape; 113 foreach (var s in vm.Shapes) s.IsSelected = false; 114 shape.IsSelected = true; 115 116 rectangle.CaptureMouse(); 117 draggingRect = rectangle; 118 119 var p = e.GetPosition(rectangle); 120 var x = (int)(p.X + 5) / 10 * 10; 121 var y = (int)(p.Y + 5) / 10 * 10; 122 startPoint = new Point(x, y); 123 124 e.Handled = true; 125 } 126 } 127 private void Rectangle_MouseMove(object sender, MouseEventArgs e) 128 { 129 if (draggingRect != sender) return; 130 131 if (sender is Rectangle { DataContext: ShapeItem shape } rectangle) 132 { 133 var p = e.GetPosition(MyCanvas); 134 var x = (int)(p.X + 5) / 10 * 10; 135 var y = (int)(p.Y + 5) / 10 * 10; 136 137 shape.X = x - startPoint.X; 138 shape.Y = y - startPoint.Y; 139 140 e.Handled = true; 141 } 142 } 143 private void Rectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 144 { 145 if (draggingRect != sender) return; 146 147 if (sender is Rectangle rectangle) 148 { 149 rectangle.ReleaseMouseCapture(); 150 draggingRect = null; 151 152 e.Handled = true; 153 } 154 } 155}

NuGet Gallery | CommunityToolkit.Mvvm 8.2.0

投稿2023/06/26 16:49

TN8001

総合スコア9326

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

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

0

この回答はGPT-4による自動生成回答です

データバインディングを使用して、DataGridの選択行とRectangleの選択を同期させることができます。以下の手順で実装してみてください。

  1. ViewModelクラスにSelectedRectプロパティを追加します。

csharp

1public class ViewModel : INotifyPropertyChanged 2{ 3 // 既存のプロパティは省略 4 5 private MyRect _selectedRect; 6 public MyRect SelectedRect 7 { 8 get { return _selectedRect; } 9 set 10 { 11 _selectedRect = value; 12 OnPropertyChanged(nameof(SelectedRect)); 13 } 14 } 15 16 // INotifyPropertyChangedの実装は省略 17}
  1. DataGridSelectedItemプロパティをSelectedRectにバインドします。

xml

1<DataGrid ItemsSource="{Binding MyRects}" SelectedItem="{Binding SelectedRect}"> 2 <!-- 他の設定は省略 --> 3</DataGrid>
  1. Rectangleを選択したときに、SelectedRectを更新するようにMainWindow.xaml.csを修正します。

csharp

1private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 2{ 3 activeRect = sender as System.Windows.Shapes.Rectangle; 4 if (activeRect == null) return; 5 if (e.LeftButton != MouseButtonState.Pressed) return; 6 activeRect.Fill = Brushes.AliceBlue; 7 8 // 選択したRectangleに対応するMyRectを検索し、SelectedRectに設定 9 var selectedMyRect = ((ViewModel)DataContext).MyRects.FirstOrDefault(r => r.Rectangle == activeRect); 10 if (selectedMyRect != null) 11 { 12 ((ViewModel)DataContext).SelectedRect = selectedMyRect; 13 } 14}

この実装により、Rectangleを選択すると、対応するDataGridの行が選択されるようになります。ただし、MyRectクラスにRectangleプロパティを追加し、RectangleMyRectを関連付ける必要があります。以下のようにMyRectクラスを修正してください。

csharp

1public class MyRect 2{ 3 // 既存のプロパティは省略 4 5 public System.Windows.Shapes.Rectangle Rectangle { get; set; } 6}

そして、MainWindow.xaml.csMyCanvas_MouseLeftButtonUpメソッドで、NowRect.Rectanglerectangleを設定します。

csharp

1private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 2{ 3 // 既存のコードは省略 4 5 MyRect NowRect = new RectangleItem { X = R_X, Y = R_Y, Width = R_W, Height = R_H, Rectangle = rectangle }; 6 ((ViewModel)DataContext).MyRects.Add(NowRect); 7 8 // 既存のコードは省略 9}

これで、Rectangleの選択とDataGridの選択行が同期されるようになります。

投稿2023/06/26 07:07

teratail-ai

Powered by GPT-4

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

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

0

例えば動的追加ができているならそれはオミットし、最初から四角が入ったコレクションを用意してください(このままでは到底1万字に収まらなくなります)

というのはこういうことです。

xml

1<Window 2 x:Class="QQj700zzpncph60k.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:QQj700zzpncph60k" 6 Width="800" 7 Height="450"> 8 <Window.Resources> 9 <DataTemplate DataType="{x:Type local:RectangleItem}"> 10 <Rectangle 11 Width="{Binding Width}" 12 Height="{Binding Height}" 13 Fill="{Binding Fill}" 14 Focusable="True" 15 MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" 16 MouseLeftButtonUp="Rectangle_MouseLeftButtonUp" 17 Stroke="{Binding Stroke}" 18 StrokeThickness="{Binding StrokeThickness}" /> 19 </DataTemplate> 20 </Window.Resources> 21 22 <Grid> 23 <ItemsControl ItemsSource="{Binding Shapes}"> 24 <ItemsControl.ItemsPanel> 25 <ItemsPanelTemplate> 26 <Canvas Background="Transparent" /> 27 </ItemsPanelTemplate> 28 </ItemsControl.ItemsPanel> 29 <ItemsControl.ItemContainerStyle> 30 <Style> 31 <Setter Property="Canvas.Left" Value="{Binding X}" /> 32 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 33 </Style> 34 </ItemsControl.ItemContainerStyle> 35 </ItemsControl> 36 </Grid> 37</Window>

cs

1using System.Collections.ObjectModel; 2using System.Windows; 3using System.Windows.Documents; 4using System.Windows.Input; 5using System.Windows.Media; 6using System.Windows.Shapes; 7using CommunityToolkit.Mvvm.ComponentModel; 8 9namespace QQj700zzpncph60k; 10 11 12public partial class RectangleItem : ObservableObject 13{ 14 [ObservableProperty] private double x; 15 [ObservableProperty] private double y; 16 [ObservableProperty] private double width; 17 [ObservableProperty] private double height; 18 [ObservableProperty] private bool isSelected; 19 20 [ObservableProperty] private double strokeThickness = 3; 21 [ObservableProperty] private Brush stroke = Brushes.Red; 22 [ObservableProperty] private Brush fill = Brushes.Transparent; 23} 24 25public partial class ViewModel : ObservableObject 26{ 27 public ObservableCollection<RectangleItem> Items { get; } = new(); 28} 29 30public partial class MainWindow : Window 31{ 32 private readonly ViewModel vm = new(); 33 34 public MainWindow() 35 { 36 InitializeComponent(); 37 DataContext = vm; 38 39 vm.Items.Add(new RectangleItem { X = 100, Y = 100, Width = 100, Height = 100, }); 40 vm.Items.Add(new RectangleItem { X = 200, Y = 200, Width = 200, Height = 200, }); 41 } 42 43 private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 44 { 45 e.Handled = true; 46 } 47 private void Rectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 48 { 49 if (sender is Rectangle rect) 50 { 51 rect.Focus(); 52 53 var adorner = new ResizeAdorner(rect); 54 AdornerLayer.GetAdornerLayer(rect).Add(adorner); 55 56 RoutedEventHandler handler = null!; // ラムダでイベント削除する場合のtips 57 handler = (_, _) => 58 { 59 rect.LostFocus -= handler; 60 AdornerLayer.GetAdornerLayer(rect).Remove(adorner); 61 }; 62 rect.LostFocus += handler; 63 64 e.Handled = true; 65 } 66 } 67}

xml:Generic.xaml

1<ResourceDictionary 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:local="clr-namespace:QQj700zzpncph60k"> 5 6 <!-- リサイズハンドルをできるだけ簡単にするためThumbを使用 --> 7 <Style TargetType="{x:Type local:CustomControl1}"> 8 <Setter Property="Template"> 9 <Setter.Value> 10 <ControlTemplate TargetType="{x:Type local:CustomControl1}"> 11 <ControlTemplate.Resources> 12 <Style TargetType="Thumb"> 13 <Setter Property="Template"> 14 <Setter.Value> 15 <ControlTemplate TargetType="Thumb"> 16 <Rectangle 17 MinWidth="10" 18 MinHeight="10" 19 Margin="-5" 20 Fill="Transparent" /> 21 </ControlTemplate> 22 </Setter.Value> 23 </Setter> 24 </Style> 25 </ControlTemplate.Resources> 26 <Grid> 27 <!-- 選択中枠 --> 28 <Rectangle Margin="-4" Stroke="Black" StrokeDashArray="4 4" /> 29 30 <!-- 全体 移動用 --> 31 <Thumb HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Cursor="SizeAll" /> 32 33 <!-- 辺 リサイズ用 --> 34 <Thumb HorizontalAlignment="Left" VerticalAlignment="Stretch" Cursor="SizeWE" /> 35 <Thumb HorizontalAlignment="Right" VerticalAlignment="Stretch" Cursor="SizeWE" /> 36 <Thumb HorizontalAlignment="Stretch" VerticalAlignment="Top" Cursor="SizeNS" /> 37 <Thumb HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Cursor="SizeNS" /> 38 39 <!-- 角 リサイズ用 --> 40 <Thumb HorizontalAlignment="Left" VerticalAlignment="Top" Cursor="SizeNWSE" /> 41 <Thumb HorizontalAlignment="Right" VerticalAlignment="Top" Cursor="SizeNESW" /> 42 <Thumb HorizontalAlignment="Left" VerticalAlignment="Bottom" Cursor="SizeNESW" /> 43 <Thumb HorizontalAlignment="Right" VerticalAlignment="Bottom" Cursor="SizeNWSE" /> 44 </Grid> 45 </ControlTemplate> 46 </Setter.Value> 47 </Setter> 48 </Style> 49 50</ResourceDictionary>

cs

1using System; 2using System.Windows; 3using System.Windows.Controls; 4using System.Windows.Controls.Primitives; 5using System.Windows.Documents; 6using System.Windows.Input; 7using System.Windows.Media; 8 9namespace QQj700zzpncph60k; 10 11 12// RectangleItemのDataTemplateにLine等ゴテゴテ付くのはイヤだし、 13// かといってCanvasに直接入れるわけにもいかない。こういう時はAdorner 14public class ResizeAdorner : Adorner 15{ 16 private readonly Control content; 17 18 public ResizeAdorner(UIElement adornedElement) : base(adornedElement) 19 { 20 content = new CustomControl1((FrameworkElement)adornedElement); 21 AddVisualChild(content); 22 AddLogicalChild(content); 23 } 24 25 protected override Size MeasureOverride(Size constraint) => AdornedElement.DesiredSize; 26 protected override Size ArrangeOverride(Size finalSize) 27 { 28 content.Arrange(new Rect(AdornedElement.DesiredSize)); 29 return AdornedElement.DesiredSize; 30 } 31 protected override int VisualChildrenCount => 1; 32 protected override Visual GetVisualChild(int index) => content; 33} 34 35// Adorner自体はxamlで作れないので中身部分はカスタムコントロール 36public class CustomControl1 : Control 37{ 38 private readonly FrameworkElement adornedElement; 39 40 private FrameworkElement canvas = null!; 41 private FrameworkElement container = null!; 42 43 private Point topLeft; 44 private Point bottomRight; 45 private Vector offset; 46 47 static CustomControl1() => DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1))); 48 public CustomControl1(FrameworkElement adornedElement) 49 { 50 this.adornedElement = adornedElement; 51 52 AddHandler(Thumb.DragStartedEvent, new DragStartedEventHandler(DragStarted)); 53 AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(DragDelta)); 54 } 55 56 public override void OnApplyTemplate() 57 { 58 base.OnApplyTemplate(); 59 60 container = adornedElement; 61 while (true) 62 { 63 var parent = VisualTreeHelper.GetParent(container) as FrameworkElement ?? throw new InvalidOperationException(); 64 if (parent is Canvas c) 65 { 66 canvas = c; 67 break; 68 } 69 container = parent; 70 } 71 } 72 73 private void DragStarted(object sender, DragStartedEventArgs e) 74 { 75 topLeft = new Point(Canvas.GetLeft(container), Canvas.GetTop(container)); 76 bottomRight = topLeft + new Vector(adornedElement.Width, adornedElement.Height); 77 offset = Mouse.GetPosition(canvas) - topLeft; 78 } 79 private void DragDelta(object sender, DragDeltaEventArgs e) 80 { 81 if (e.OriginalSource is Thumb thumb) 82 { 83 var p = Mouse.GetPosition(canvas); 84 85 // 移動 86 if (thumb.HorizontalAlignment == HorizontalAlignment.Stretch 87 && thumb.VerticalAlignment == VerticalAlignment.Stretch) 88 { 89 var pp = p - offset; 90 Canvas.SetLeft(container, pp.X); 91 Canvas.SetTop(container, pp.Y); 92 return; 93 } 94 95 // リサイズ 96 var (x1, x2) = thumb.HorizontalAlignment switch 97 { 98 HorizontalAlignment.Left => (p.X, bottomRight.X), 99 HorizontalAlignment.Right => (topLeft.X, p.X), 100 _ => (topLeft.X, bottomRight.X), 101 }; 102 var (y1, y2) = thumb.VerticalAlignment switch 103 { 104 VerticalAlignment.Top => (p.Y, bottomRight.Y), 105 VerticalAlignment.Bottom => (topLeft.Y, p.Y), 106 _ => (topLeft.Y, bottomRight.Y), 107 }; 108 109 var width = x2 - x1; 110 Canvas.SetLeft(container, width < 0 ? x2 : x1); 111 adornedElement.Width = Math.Abs(width); 112 113 var height = y2 - y1; 114 Canvas.SetTop(container, height < 0 ? y2 : y1); 115 adornedElement.Height = Math.Abs(height); 116 } 117 } 118}

NuGet Gallery | CommunityToolkit.Mvvm 8.2.0

投稿2023/06/26 16:44

編集2023/06/26 17:10
TN8001

総合スコア9326

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

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

TN8001

2023/06/26 16:47

エラー MC3000 '指定されたエンコードに無効な文字があります。 行 26、位置 19。.' XML が無効です。 のようなエラーが出たらGeneric.xamlのコメントを削除するか、UTF-8で上書き保存してください(デフォのテンプレートがShift_JISくさい)
TN8001

2023/06/26 16:47

基本的にはこの辺を参考にしました。 [wpf adorner resize - Google 検索](https://www.google.co.jp/search?q=wpf+adorner+resize) 出来上がっているのを見れば簡単そうに見えますが、土日がつぶれていますw 恩着せがましく言ってるんではなく、「凡人には難しいですよ」ってことです^^;
nodoita

2023/07/04 01:21

土日を削ってまで対応頂きありがとうございますorz まだちょっと分からない点があるため質問させて頂くかもしれません。 そもそも考え方が違う…となりそうな気もしますが 申し訳ありませんが回答頂ければ嬉しいです。 いつも本当にありがとうございます!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問