自分用バックアップ2020_01_15_23_00(安定版)
思っていたところまで形にできました!このままでもいいかもだけど、後はできれば各 Thumb に何らかの Model データをバインドさせておいて、移動前の位置データと移動後の位置データを見ることができればとりあえずは終わりです。後はこの2つのデータをロジックに渡してごにょごにょすれば完成ですね!
多分、数日後の自分が読み返したら、何をしたかったんだろう?何に使うんだろう?と思って、思い出せずに後悔することでしょう。ガッハッハ!
目次
イメージ
XAML
<Window x:Class="WpfApp17.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:WpfApp17" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <DockPanel> <StackPanel DockPanel.Dock="Right" Width="100" Margin="10,30,10,0"> <Button x:Name="button1" Content="button1" Height="50" Margin="0,0,0,10" /> <Button IsEnabled="False" Content="button2" Height="50" Margin="0,0,0,10" /> <Button IsEnabled="False" Content="button3" Height="50" Margin="0,0,0,10" /> <Button IsEnabled="False" Content="button3" Height="50" Margin="0,0,0,10" /> </StackPanel> <Canvas SnapsToDevicePixels="True" Margin="30"> <Canvas.Background> <VisualBrush TileMode="Tile" Viewbox="0,0,100,100" ViewboxUnits="Absolute" Viewport="0,0,100,100" ViewportUnits="Absolute"> <VisualBrush.Visual> <Rectangle Stroke="DarkGray" StrokeThickness="1" Width="100" Height="100" StrokeDashArray="5 5" /> </VisualBrush.Visual> </VisualBrush> </Canvas.Background> <Thumb x:Name="thumb1" Canvas.Top="0" Canvas.Left="0" DragDelta="Thumb_DragDelta"> <Thumb.Template> <ControlTemplate> <Grid Margin="10"> <Rectangle Width="80" Height="80" Stroke="Blue" StrokeThickness="1" Fill="AliceBlue" RadiusX="20" RadiusY="20" /> <TextBlock Text="textBlock1" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Thumb.Template> </Thumb> <Thumb x:Name="thumb2" Canvas.Top="100" Canvas.Left="300" DragDelta="Thumb_DragDelta"> <Thumb.Template> <ControlTemplate> <Grid Margin="10"> <Rectangle Width="80" Height="80" Stroke="Red" StrokeThickness="1" Fill="LightPink" RadiusX="20" RadiusY="20" /> <TextBlock Text="textBlock2" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Thumb.Template> </Thumb> <Thumb x:Name="thumb3" Canvas.Top="0" Canvas.Left="400" DragDelta="Thumb_DragDelta"> <Thumb.Template> <ControlTemplate> <Grid Margin="10"> <Rectangle Width="80" Height="80" Stroke="Red" StrokeThickness="1" Fill="LightPink" RadiusX="20" RadiusY="20" /> <TextBlock Text="textBlock3" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Thumb.Template> </Thumb> </Canvas> </DockPanel> </Window>
コードビハインド
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace WpfApp17 { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); // Loaded += (s, e) => { Console.WriteLine($"({Canvas.GetLeft(thumb1)}, {Canvas.GetTop(thumb1)}): thumb1"); Console.WriteLine($"({Canvas.GetLeft(thumb2)}, {Canvas.GetTop(thumb2)}): thumb2"); Console.WriteLine($"({Canvas.GetLeft(thumb3)}, {Canvas.GetTop(thumb3)}): thumb3"); }; button1.Click += (s, e) => { Console.WriteLine($"({Canvas.GetLeft(thumb1)}, {Canvas.GetTop(thumb1)}): thumb1"); Console.WriteLine($"({Canvas.GetLeft(thumb2)}, {Canvas.GetTop(thumb2)}): thumb2"); Console.WriteLine($"({Canvas.GetLeft(thumb3)}, {Canvas.GetTop(thumb3)}): thumb3"); }; } private void Thumb_DragDelta(object sender, DragDeltaEventArgs e) { var target = sender as Thumb; if (target is null) return; var canvas1 = target.Parent as Canvas; if (canvas1 is null) return; // 現在 Canvas 上にいる位置のうち左上の位置(X, Y) に、移動量を加えて、 // 実際に移動させるかどうか(Canvas.SetXxx() を呼ぶかどうか)を判定する var currentX = Canvas.GetLeft(target); var currentY = Canvas.GetTop(target); var nextX = currentX + e.HorizontalChange; var nextY = currentY + e.VerticalChange; // 100px 単位の移動に制限させる。(0, 0) を右に移動したら次の左上の位置は (100, 0) となる nextX = Math.Round(nextX / 100.0) * 100; nextY = Math.Round(nextY / 100.0) * 100; // 画面の端を超えそうになったら、吸着させて飛び越えさせない if (IsWall(canvas1, target, nextX, nextY)) return; // 実際に移動する Canvas.SetLeft(target, nextX); Canvas.SetTop(target, nextY); // 移動後の場所に、別の物体があった場合は、元の位置に戻る // 移動中の Thumb を除く他の Thumb リストを取得 var others = canvas1.Children.OfType<Thumb>().Where(other => other != target); if (IsSamePlace(others, nextX, nextY)) { if (currentX != nextX) { if (e.HorizontalChange != 0) { // プラス値・・・右に移動したので、左に戻る // マイナス値・・・左に移動したので、右に戻る if (0 < e.HorizontalChange) nextX -= 100; if (e.HorizontalChange < 0) nextX += 100; Canvas.SetLeft(target, nextX); } } if (currentY != nextY) { if (e.VerticalChange != 0) { // プラス値・・・下に移動したので、上に戻る // マイナス値・・・上に移動したので、下に戻る if (0 < e.VerticalChange) nextY -= 100; if (e.VerticalChange < 0) nextY += 100; Canvas.SetTop(target, nextY); } } } } private bool IsWall(Canvas canvas1, Thumb target, double nextX, double nextY) { if (nextX < 0) return true; if (nextY < 0) return true; if (canvas1.ActualWidth < nextX + target.ActualWidth) return true; if (canvas1.ActualHeight < nextY + target.ActualHeight) return true; return false; } private bool IsSamePlace(IEnumerable<Thumb> others, double x, double y) { if (others is null) return false; if (!others.Any()) return false; foreach (var other in others) { var otherX = Canvas.GetLeft(other); var otherY = Canvas.GetTop(other); if (x == otherX && y == otherY) return true; } return false; } } }