午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

WPFとVBでアプリ作る準備その3、ImageコントロールにDragDeltaイベントがほしくて擬似DragDelta

前回
の続き
 
 
3回めになるコントロールのドラッグ移動
また少し思い描いていたものに近づいた
画像ファイルドロップで表示した画像をマウスドラッグできるようにするのに
ImageコントロールにDragDeltaイベントがあればいいなあ
でも方法がわからないなあってのが少しなんとかなったかも
 
イメージ 19
動きは前回、前々回と全く同じはず
 
Imageを継承したクラスを作成して、OnMouseMoveメソッドを
Overridesして、その中でDragDeltaイベントを発生させて
DragDeltaイベントがあるように見せかけるっていうの
 
Public Class ExImage
    Inherits Image
Public Event ExDragDelta(sender As Object, e As DragDeltaEventArgs)
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
RaiseEvent ExDragDelta(Me, New DragDeltaEventArgs(p.X, p.Y))
End Sub
End Class
 
こんなかんじ
もっとまともな方法があると思うんだけどわからないし
OverridesとかRaiseEventとか理解できていないんだけどね
今のところ期待通りに動いている
全体のコードの様子は
Imageクラスを継承して作ったExImageクラス

f:id:gogowaten:20191025101118p:plain

名前はExImageにした
Imports System.Windows.Controls.Primitives

Public Class ExImage
    Inherits Image
    Private _p As Point
    Public Event ExDragDelta(sender As Object, e As DragDeltaEventArgs)
    Protected Overrides Sub OnMouseLeftButtonDown(e As MouseButtonEventArgs)
        MyBase.OnMouseLeftButtonDown(e)
        _p = e.GetPosition(Me)
        Me.CaptureMouse()
    End Sub
    Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
        MyBase.OnMouseMove(e)
        If e.LeftButton = MouseButtonState.Pressed Then
            Dim p As Point = Point.Subtract(e.GetPosition(Me), _p)
            RaiseEvent ExDragDelta(Me, New DragDeltaEventArgs(p.X, p.Y))
        End If
    End Sub
    Protected Overrides Sub OnMouseUp(e As MouseButtonEventArgs)
        MyBase.OnMouseUp(e)
        Me.ReleaseMouseCapture()
    End Sub
End Class
DragDeltaEventArgsを引数に持たせたExDragDeltaと言う
名前を付けたイベントを宣言?しておく
 
OnMouseLeftButtonDownで
左クリックした時にクリックした位置を記録して
 
OnMouseMoveで
マウスが動いた時に今の位置と記録した位置から移動距離を出して
RaiseEventでExDragDeltaを起動する、この時引数に移動距離を持たせる
 
 
ドラッグ事にマウスを早く動かし過ぎると動かしているコントロールから
マウスが離れないようにするために
左クリック時にMe.CaptureMouseでくっつけて
クリックを離した時にMe.ReleaseMouseCaptureで放している

 
デザイン画面

f:id:gogowaten:20191025101134p:plain

前回と一緒でWindowにAllowDropをTrue指定して
canvas1って言う名前をつけたCanvasを設置しただけ
 
VBコード

f:id:gogowaten:20191025101147p:plain

Imports System.IO
Imports System.Windows.Controls.Primitives

Class MainWindow
    'マウスドラッグ移動
    Private Sub ExImage_DragMove(sender As Object, e As DragDeltaEventArgs)
        Canvas.SetLeft(sender, e.HorizontalChange + Canvas.GetLeft(sender))
        Canvas.SetTop(sender, e.VerticalChange + Canvas.GetTop(sender))
    End Sub

    'ファイルパスからBitmapImage(画像)を作成して返す
    Private Function GetBitmapImage(filePath As String) As BitmapImage
        Dim bmp As New BitmapImage
        Using fs As New FileStream(filePath, FileMode.Open, FileAccess.Read)
            With bmp
                .BeginInit()
                .StreamSource = fs
                .CacheOption = BitmapCacheOption.OnLoad
                .EndInit()
                .Freeze()
            End With
        End Using
        Return bmp
    End Function

    'ExImageを作成して追加
    Private Sub AddExImage(filesPath As String, locate As Point)
        Dim t As New ExImage
        canvas1.Children.Add(t)
        t.Source = GetBitmapImage(filesPath)
        Canvas.SetLeft(t, locate.X) '表示する位置は必須、指定しないとDragdeltaイベントで移動量が取得できない
        Canvas.SetTop(t, locate.Y)  '必須
        AddHandler t.ExDragDelta, AddressOf ExImage_DragMove 'これはマウスドラッグ用
    End Sub

    'ウィンドウに画像ファイルがドロップされた時
    Private Sub MainWindow_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop
        Dim filesPath() As String = e.Data.GetData(DataFormats.FileDrop) 'ファイルパス取得
        Dim locate As New Point(0, 0) 'ExImageを表示する位置
        For i As Integer = 0 To filesPath.Length - 1
            Call AddExImage(filesPath(i), locate) 'ExImage作成表示
            locate.Offset(30, 30) '位置の変更
        Next
    End Sub

End Class
 

イメージ 17
ドラッグ移動の部分は
まるでDragDeltaイベントが有るかのような振る舞いw
なのでThumbコントロールの時と全く同じで簡潔になっている
 
今気づいた
イメージ 20
Canvas.SetLeftとかのCanvasって部分は
Imports System.Window.Controls.Canvasって書いとけば
SetLeftだけでも動く
 

f:id:gogowaten:20191025101202p:plain

やっていることはほとんど同じだから、あんまり変わらないかな?
 
今回の方法はよくわかっていないので
なにか気づいていない良くない副作用があるかもしれないけど
気に入っているからこれで行こうかなあと
 
 
参照したところは
VB イベントの作成 - Event, RaiseEvent, WithEvents
http://homepage1.nifty.com/rucio/main/dotnet/shokyu/standard49.htm
アプリが作れるようになったのはこのVB中学校のおかげ
あれから2年経ったけど未だに初級講座のところも理解できていないw
デリゲート…インターフェイス…マルチスレッド(゚д゚)?
 
 
 
WPF_test4 (master) - Visual Studio Team Services
https://gogowaten.visualstudio.com/DefaultCollection/WPF/_git/WPF_test4
Wpf_test55_Imageコントロールを擬似DragDeltaでマウスドラッグ移動
 
 
 
 

クラスを追加するときは

f:id:gogowaten:20191025101215p:plain

メニューのプロジェクト→クラスの追加
 

f:id:gogowaten:20191025101225p:plain

適当な名前(Class1とか)を付けて追加ボタン
 

f:id:gogowaten:20191025101234p:plain

Class1クラスが追加された
 
作った後からクラスの名前を変える時は
イメージ 5
クラスの名前を右クリック→名前の変更
イメージ 6
クラスの名前が選択された状態になるので書き換える
 
イメージ 7
エンターキーを押せば完了
このクラスを参照しているところも全て変更される
 
ファイル名?も変更する

f:id:gogowaten:20191025101251p:plain

ソリューションエクスプローラに表示されている名前も変更するには
 

f:id:gogowaten:20191025101302p:plain

ソリューションエクスプローラに表示されているクラスを右クリック
→名前の変更
 
イメージ 10
編集できるようになる
 

f:id:gogowaten:20191025101314p:plain

変更できた
 

 
MouseMoveイベントの時の動作を改変する?には
OnMouseMoveメソッドをOverrides
イメージ 12
Overridesって打ってスペース入れるとOverridesできるもの一覧が表示される
続けてMoveって打つと
 
イメージ 13
絞込される、OnMouseMoveを選択してTabキーを押すと
 
イメージ 14
最低限必要なことなんだろうと思われるものが自動で入力される
 
 
 
 
 
WPFVBでアプリ作る準備その4、コントロールを重ねた時の上下移動(ZOrder)はPanel.SetZIndex ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13913897.html
 
2016年5月22日追記

gogowaten.hatenablog.com

 
WPFVB.NET、ControlTemplateを使ったThumbを回転表示する時に回転させるのはどれがいいのか ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14157487.html