お世話になります。
調べたのですが、分からないため教えてください。
実現したいこと
Rectangleのどの位置にカーソルが居るのかでカーソルを変化させようとしています。
しかし、RectangleのCanvasLeft,Topが取得できなくて困ってます。
実現したいこととしては、以下です。
①作成済みのRectangleをクリック→Rectangleにフォーカスが当たる
②フォーカスの当たっているRectangleの中心は移動カーソル、端は拡縮カーソル表示
③カーソルの状態でRectangleを編集する
とりあえず、フォーカスよりも前にRectangleのCanvasLeft/Topを取得したいです。
前提
BindingとかMVVMの理解が浅いです。
色々と手探りで作りながら勉強をしていますが
1つずつコツコツ自分のやりたいことを実現しながら学んでいきたいと思ってます。
継ぎはぎで見づらいソースで申し訳ありません。
このソースの改良点等もあれば教えていただきたいです。
該当のソースコード
MainWindow.xaml
1 <Window.Resources> 2 <DataTemplate DataType="{x:Type local:RectangleItem}"> 3 <Rectangle Width="{Binding Width}" Height="{Binding Height}" Fill="{Binding Fill}" StrokeThickness="{Binding StrokeThickness}" Stroke="{Binding Stroke}" Canvas.ZIndex="0" 4 Focusable="True" MouseLeftButtonDown="Rectangle_MouseLeftButtonDown" MouseLeftButtonUp="Rectangle_MouseLeftButtonUp" MouseMove="Rectangle_MouseMove"/> 5 </DataTemplate> 6 </Window.Resources> 7 <DockPanel LastChildFill="False"> 8 <ToolBar VerticalAlignment="Top" DockPanel.Dock="Top" > 9 <RadioButton x:Name="DefaultButton" Width="32" Height="32" 10 Content="?" IsChecked="True" /> 11 <RadioButton x:Name="RectButton" Width="32" Height="32"> 12 <Rectangle Width="24" Height="16" Stroke="Black"/> 13 </RadioButton> 14 </ToolBar> 15 <Canvas x:Name="MyCanvas" Width="1000" Height="800" Background="Transparent" MouseLeftButtonDown="MyCanvas_MouseLeftButtonDown" MouseLeftButtonUp="MyCanvas_MouseLeftButtonUp" MouseMove="MyCanvas_MouseMove" MouseLeave="MyCanvas_MouseLeave"> 16 <ItemsControl ItemsSource="{Binding MyRects}" Panel.ZIndex="255"> 17 <ItemsControl.ItemsPanel> 18 <ItemsPanelTemplate> 19 <Canvas /> 20 </ItemsPanelTemplate> 21 </ItemsControl.ItemsPanel> 22 <ItemsControl.ItemContainerStyle> 23 <Style> 24 <Setter Property="Canvas.Left" Value="{Binding X}" /> 25 <Setter Property="Canvas.Top" Value="{Binding Y}" /> 26 </Style> 27 </ItemsControl.ItemContainerStyle> 28 </ItemsControl> 29 <Image MinWidth="1000" MinHeight="800" MaxWidth="1000" MaxHeight="800" Width="1000" Height="800" Source="1.png" StretchDirection="DownOnly" HorizontalAlignment="Left" VerticalAlignment="Top" /> 30 </Canvas> 31 </DockPanel> 32</Window>
MainWindow.xaml.cs
1namespace TEST 2{ 3 public partial class MainWindow : Window 4 { 5 bool isMouseDown = false; 6 Point StartPoint; 7 Point MovePoint; 8 public string MouseNow = ""; 9 System.Windows.Shapes.Rectangle rectangle; 10 private System.Windows.Shapes.Rectangle? activeRect; 11 public MainWindow() 12 { 13 InitializeComponent(); 14 DataContext = new ViewModel(); 15 } 16 17 private void MyCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 18 { 19 var point = e.GetPosition(MyCanvas); 20 21 var leftOffset = point.X % 10; 22 leftOffset = leftOffset < 5 ? -leftOffset : 10 - leftOffset; 23 var topOffset = point.Y % 10; 24 topOffset = topOffset < 5 ? -topOffset : 10 - topOffset; 25 26 StartPoint = new Point(point.X + leftOffset, point.Y + topOffset); 27 28 rectangle = new System.Windows.Shapes.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 Panel.SetZIndex(rectangle, 0);//最前面表示 40 Canvas.SetLeft(rectangle, StartPoint.X); 41 Canvas.SetTop(rectangle, StartPoint.Y); 42 MyCanvas.Children.Add(rectangle); 43 isMouseDown = true; 44 } 45 46 private void MyCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 47 { 48 var R_X = StartPoint.X; 49 var R_Y = StartPoint.Y; 50 if (MovePoint.X - StartPoint.X <= 0) 51 { 52 R_X = MovePoint.X; 53 } 54 if (MovePoint.Y - StartPoint.Y <= 0) 55 { 56 R_Y = MovePoint.Y; 57 } 58 59 var R_H = rectangle.Height; 60 var R_W = rectangle.Width; 61 62 MyCanvas.Children.Remove(rectangle); 63 MyRect NowRect = new RectangleItem { X = R_X, Y = R_Y, Width = R_W, Height = R_H }; 64 ((ViewModel)DataContext).MyRects.Add(NowRect); 65 66 isMouseDown = false; 67 rectangle.Opacity = 1; 68 } 69 70 private void MyCanvas_MouseMove(object sender, MouseEventArgs e) 71 { 72 if (!isMouseDown) return; 73 74 var point = e.GetPosition(MyCanvas); 75 76 var leftOffset = point.X % 10; 77 leftOffset = leftOffset < 5 ? -leftOffset : 10 - leftOffset; 78 var topOffset = point.Y % 10; 79 topOffset = topOffset < 5 ? -topOffset : 10 - topOffset; 80 81 MovePoint = new Point(point.X + leftOffset, point.Y + topOffset); 82 rectangle.Width = Math.Abs(MovePoint.X - StartPoint.X); 83 rectangle.Height = Math.Abs(MovePoint.Y - StartPoint.Y); 84 85 if (MovePoint.X - StartPoint.X <= 0) 86 { 87 Canvas.SetLeft(rectangle, MovePoint.X); 88 } 89 if (MovePoint.Y - StartPoint.Y <= 0) 90 { 91 Canvas.SetTop(rectangle, MovePoint.Y); 92 } 93 } 94 95 private void Rectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 96 { 97 activeRect = sender as System.Windows.Shapes.Rectangle; 98 if (activeRect == null) return; 99 100 if (e.LeftButton != MouseButtonState.Pressed) 101 { 102 return; 103 } 104 activeRect.Fill = Brushes.AliceBlue;//クリックしたら青色にする(確認のため) 105 } 106 107 private void Rectangle_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 108 { 109 Cursor = Cursors.Arrow;//カーソルをデフォルトに 110 } 111 112 private void Rectangle_MouseMove(object sender, MouseEventArgs e) 113 { 114 //マウスポインタの座標を取得 115 var p = e.GetPosition(MyCanvas); 116 activeRect = sender as System.Windows.Shapes.Rectangle; 117 118 if (activeRect != null) { 119 HitTest(p, activeRect); 120 } 121 122 if (e.LeftButton == MouseButtonState.Pressed) 123 { 124 if (activeRect is null) 125 { return; } 126 } 127 else 128 { 129 130 } 131 } 132 133 public virtual bool HitTest(Point p, System.Windows.Shapes.Rectangle nowRect) 134 { 135 Point activeXY = new Point(Canvas.GetLeft(nowRect), Canvas.GetTop(nowRect)); 136 Point activeWH = new Point(activeXY.X + nowRect.ActualWidth, activeXY.Y + nowRect.ActualHeight); 137 138 if (nowRect.Fill is not null) 139 { 140 //図形内部の当たり判定 141 if (activeXY.X <= p.X && p.X <= activeXY.Y 142 && activeXY.Y <= p.Y && p.Y <= activeWH.Y) 143 { 144 MouseNow = "移動"; 145 return true; 146 } 147 } 148 if (nowRect.Stroke is not null) 149 { 150 if (p.X >= activeXY.X && p.X <= activeWH.X 151 && p.Y >= activeXY.Y - 2 && p.Y <= activeWH.Y + 2) 152 { 153 MouseNow = "上下"; 154 return true; 155 } 156 if (p.X >= activeXY.X && p.X <= activeXY.Y 157 && p.Y >= activeWH.Y - 2 && p.Y <= activeWH.Y + 2) 158 { 159 MouseNow = "上下"; 160 return true; 161 } 162 if (p.Y >= activeXY.Y && p.Y <= activeWH.Y 163 && p.X >= activeXY.X - 2 && p.X <= activeXY.X + 2) 164 { 165 MouseNow = "左右"; 166 return true; 167 } 168 if (p.Y >= activeXY.Y && p.Y <= activeWH.Y 169 && p.X >= activeXY.Y - 2 && p.X <= activeXY.Y + 2) 170 { 171 MouseNow = "左右"; 172 return true; 173 } 174 } 175 return false; 176 } 177 } 178} 179
MyRect.cs
1namespace TEST; 2 public class MyRect 3 { 4 public double X { get; set; } 5 public double Y { get; set; } 6 public double Width { get; set; } 7 public double Height { get; set; } 8 } 9 10 public class RectangleItem : MyRect 11 { 12 public double StrokeThickness { get; set; } = 3; 13 public Brush Stroke { get; set; } = Brushes.Red; 14 public Brush Fill { get; set; } = Brushes.Transparent; 15 } 16 17
ViewModel.cs
1namespace TEST; 2 3public partial class ViewModel : ObservableObject 4{ 5 [ObservableProperty] private bool isSubWindowShown; 6 public ObservableCollection<MyRect> MyRects { get; } = new(); 7 public ViewModel() 8 { 9 } 10 11 } 12
試したこと
mainWindow.xaml.cs
1 public virtual bool HitTest(Point p, System.Windows.Shapes.Rectangle nowRect) 2 { 3 Point activeXY = new Point(Canvas.GetLeft(nowRect), Canvas.GetTop(nowRect)); 4 Point activeWH = new Point(activeXY.X + nowRect.ActualWidth, activeXY.Y + nowRect.ActualHeight); 5 }
クリックしたものだけでもRectangleの値を取得したいと思い、
とりあえず上記のようにしていました。
しかし、「Canvas.GetLeft(nowRect)」がNaNになってしまいます。
Nanになってしまうため、「Point activeXY 」が取得できません。
ブレイクポイントをつけ、nowRectを確認するとRectangleの値は入っているのですが
どうもうまく取得できていないようです。
どうしたら現在選択しているRectのCanvasLeft,Topが取得できますか?
補足情報(FW/ツールのバージョンなど)
Visualstudio2022 V17.6.3
.NET 6.0 C#

回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2023/06/23 01:56
2023/06/23 03:00
2023/06/23 04:37
2023/06/23 05:55 編集
2023/06/23 05:52
2023/06/23 08:20