トップ回答者
Rectangle.IntersectsWith

質問
回答
-
解決しました。
最初からソースを見ていて疑問に思っていたのですが、
Point controlPoint = button.PointToScreen(new Point(0d, 0d));
ではPointToScreenによりDPIが考慮されているのですが、 Rect clientRect = new Rect(controlPoint.X, controlPoint.Y, button.ActualWidth, button.ActualHeight);
におけるActualWidthとActualHeightはDPIが考慮されていないように思えます。
ここに別途取得したDPI値をかけてやれば問題なく動作するようです。
以上、皆様ありがとうございました。
Shigehiro Mori
- 回答としてマーク commune 2017年9月26日 1:31
- 回答としてマークされていない commune 2017年9月26日 1:33
- 回答としてマーク 立花楓Microsoft employee, Moderator 2017年10月11日 6:07
すべての返信
-
WPFでRectangleと言えばSystem.Windows.Shapes.Rectangleクラスを指すものと思いますが、このRectangleにはIntersectsWithがないようです。ひょっとして、System.Drawing.Rectangle構造体を利用されているのでしょうか。WPFは座標系をDouble型で扱うので、Int32型やせいぜいSingle型でしか扱えないSystem.Drawingは扱いがやや面倒だと思います。System.Windows.Rect構造体の使用をお勧めします。
さて本題ですが、今提供されている情報の範囲ではなんともいえません。具体的なコードを提示いただけませんか。
そもそもヒットテストであれば、System.Windows.Media.VisualTreeHelperのHitTestメソッドを利用できませんか?
- 回答の候補に設定 立花楓Microsoft employee, Moderator 2017年9月26日 4:17
-
早速のご返答ありがとうございます。
Rectangle.IntersectsWithと書いてしまいましたがSystem.Windows.Rect.IntersectsWithが正解のようです。すみません。
System.Windows.Media.VisualTreeHelperについて調べてみようと思います。
現状テスト用で利用しているソースは以下の通りです。
XAML: <Window x:Class="RectSelection.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:RectSelection" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525" PreviewMouseLeftButtonDown="Window_PreviewMouseLeftButtonDown" PreviewMouseLeftButtonUp="Window_PreviewMouseLeftButtonUp" MouseMove="Window_MouseMove"> <Grid> <Grid x:Name="MainGrid"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <ToggleButton Grid.Column="0" Grid.Row="0" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="1" Grid.Row="0" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="2" Grid.Row="0" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="3" Grid.Row="0" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="0" Grid.Row="1" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="1" Grid.Row="1" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="2" Grid.Row="1" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="3" Grid.Row="1" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="0" Grid.Row="2" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="1" Grid.Row="2" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="2" Grid.Row="2" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="3" Grid.Row="2" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="0" Grid.Row="3" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="1" Grid.Row="3" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="2" Grid.Row="3" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> <ToggleButton Grid.Column="3" Grid.Row="3" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10"/> </Grid> <Rectangle Name="SelectionRect" HorizontalAlignment="Left" VerticalAlignment="Top" StrokeDashArray="2,2" Stroke="LightGray" StrokeThickness="1" Visibility="Collapsed"/> </Grid> </Window> C#: using System; using System.Windows; using System.Windows.Controls.Primitives; using System.Windows.Input; namespace RectSelection { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private Point _DownedPoint = new Point(); private void Window_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { _DownedPoint = Mouse.GetPosition(this); this.SelectionRect.Margin = new Thickness(_DownedPoint.X, _DownedPoint.Y, 0, 0); this.SelectionRect.Width = 0; this.SelectionRect.Height = 0; this.SelectionRect.Visibility = Visibility.Visible; } private void Window_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e) { Point selectionPoint = this.SelectionRect.PointToScreen(new Point(this.Left, this.Top)); Rect selectionRect = new Rect(selectionPoint.X, selectionPoint.Y, this.SelectionRect.ActualWidth, this.SelectionRect.ActualHeight); foreach (var child in LogicalTreeHelper.GetChildren(MainGrid)) { if (child is ToggleButton) { ToggleButton button = child as ToggleButton; Point controlPoint = button.PointToScreen(new Point(this.Left, this.Top)); Rect clientRect = new Rect(controlPoint.X, controlPoint.Y, button.ActualWidth, button.ActualHeight); if (selectionRect.IntersectsWith(clientRect)) { button.IsChecked = true; } else { button.IsChecked = false; } } } this.SelectionRect.Width = 0; this.SelectionRect.Height = 0; this.SelectionRect.Visibility = Visibility.Hidden; } private void Window_MouseMove(object sender, MouseEventArgs e) { Point p = Mouse.GetPosition(this); if (!_DownedPoint.Equals(p)) { if (p.X - _DownedPoint.X >= 0 && p.Y - _DownedPoint.Y >= 0) { this.SelectionRect.Margin = new Thickness(_DownedPoint.X, _DownedPoint.Y, 0, 0); this.SelectionRect.Width = p.X - _DownedPoint.X; this.SelectionRect.Height = p.Y - _DownedPoint.Y; } else if (p.X - _DownedPoint.X < 0 && p.Y - _DownedPoint.Y >= 0) { this.SelectionRect.Margin = new Thickness(p.X, _DownedPoint.Y, 0, 0); this.SelectionRect.Width = _DownedPoint.X - p.X; this.SelectionRect.Height = p.Y - _DownedPoint.Y; } else if (p.X - _DownedPoint.X >= 0 && p.Y - _DownedPoint.Y < 0) { this.SelectionRect.Margin = new Thickness(_DownedPoint.X, p.Y, 0, 0); this.SelectionRect.Width = p.X - _DownedPoint.X; this.SelectionRect.Height = _DownedPoint.Y - p.Y; } else if (p.X - _DownedPoint.X < 0 && p.Y - _DownedPoint.Y < 0) { this.SelectionRect.Margin = new Thickness(p.X, p.Y, 0, 0); this.SelectionRect.Width = Math.Abs(_DownedPoint.X - p.X); this.SelectionRect.Height = Math.Abs(_DownedPoint.Y - p.Y); } } } } }
以上、よろしくお願い致します。
Shigehiro Mori
-
気になる点があるとすれば、PointToScreen に渡している座標が this.Left, this.Top という点ですね。
Window の Left/Top は Window の外枠の座標なので、それを PointToScreen で変換すると、Window.SelectionRect や button の左上から this.Left, this.Top 分ずらした位置をスクリーン座標に変換することになりますので、狙ったとおりのコードになっていないかと思われます。たとえば、Window のスクリーン座標が欲しいだけなら、(0, 0) を渡すべきなのでは?
(100% でたまたまうまくいっているように見えるだけという予想)
- 編集済み AzuleanMVP 2017年9月25日 22:28
-
解決しました。
最初からソースを見ていて疑問に思っていたのですが、
Point controlPoint = button.PointToScreen(new Point(0d, 0d));
ではPointToScreenによりDPIが考慮されているのですが、 Rect clientRect = new Rect(controlPoint.X, controlPoint.Y, button.ActualWidth, button.ActualHeight);
におけるActualWidthとActualHeightはDPIが考慮されていないように思えます。
ここに別途取得したDPI値をかけてやれば問題なく動作するようです。
以上、皆様ありがとうございました。
Shigehiro Mori
- 回答としてマーク commune 2017年9月26日 1:31
- 回答としてマークされていない commune 2017年9月26日 1:33
- 回答としてマーク 立花楓Microsoft employee, Moderator 2017年10月11日 6:07