午後わてんのブログ

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

WPFとVBでアプリ作る準備その2、ControlTemplateの中のControlを取得する

の続き
 
 
動的作成したコントロールにテンプレートを指定する
その後からテンプレートの中のコントロールを取得していろいろ設定を変更

目的は画像ファイルがアプリのウィンドウにドロップされたら表示して
マウスドラッグで移動させること…前回と一緒なんだけど
 
画像ファイルを表示するのに適したコントロールはImage
マウスドラッグで移動させるコントロールで最適なのはThumb
どちらも目的には一長一短
このふたつを組み合わせて使いたい
ググったらControlTemplate(テンプレート)ってのを使えばできそうで
なんとかできた感じ
 
画像ファイルドロップで表示しするのは後回しにして
ThumbとImageを組み合わせたものに画像を表示してみることから

f:id:gogowaten:20191025100056p:plain

Thumbコントロールの中にImageコントロールを使ったTemplateを入れる
これで画像の表示はImageコントロールに任せたThumbコントロールができる
Thumbコントロールの名前はthumb1
Imageコントロールの名前はimage1にした
image1に表示する画像ファイルの指定はボタンコントロールのクリックイベントにした
ボタンクリックイベント中身は

f:id:gogowaten:20191025100109p:plain

    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        Dim bmp As New BitmapImage(New Uri("D:\ブログ用\テスト用画像\hueRectT210.png"))
        Dim img As Image = thumb1.Template.FindName("image1", thumb1)
        img.Source = bmp
        img.Width = bmp.PixelWidth
        img.Height = bmp.PixelHeight
    End Sub

 
画像を表示するにはControlTemplateの中にあるimage1のSourceプロパティにBitmapImage(画像)を指定すればいいだけ
image1を取得するには
Template.FindNameメソッドを使う
thumb1の中のControlTemplateの中のImage1を取得するので
Dim img As Image = thumb1.Template.FindName("image1", thumb1)
これでOK
 
画像ファイルのパスからBitmapImage(画像)の作成
        Dim bmp As New BitmapImage(New Uri("D:\ブログ用\テスト用画像\hueRectT210.png"))
 
あとはimage1のSourceにBitmapImageを指定すればthumb1に画像が表示される
        img.Source = bmp
 
 
実行したところ
イメージ 3
ボタンクリックすると
 
イメージ 4
画像が表示される
OK

 
後回しにしていた画像ファイルドロップで表示するには
動的に作成したThumbコントロールにTemplateを指定する
って方法でできた
でもVBのコードでTemplateを作成する方法がわからなかったので
デザイン画面のXAMLの方でTemplateを用意しておいて
それをコードのほうで取得して指定することにした
 
デザイン画面でTemplateの用意したところ

f:id:gogowaten:20191025100125p:plain

Window.Resourcesの中にControlTemplateを入れてその中にImageを入れる
ControlTemplateのKeyをctにして
ImageのNameをimage1にしてみた
KeyやNameはVBのコードからこのControlTemplateやImageを取得するときに必要になる
 
動的作成したThumbにこのControlTemplateを指定して
その中のimage1に画像を指定すればThumbに画像が表示されることになる
 
VBコード

f:id:gogowaten:20191025100138p:plain

Imports System.Windows.Controls.Primitives 'Thumb用
Imports System.IO

Class MainWindow

    'ドラッグ移動
    Private Sub Thumb_Dragdelta(sender As Object, e As DragDeltaEventArgs)
        Canvas.SetLeft(sender, e.HorizontalChange + Canvas.GetLeft(sender))
        Canvas.SetTop(sender, e.VerticalChange + Canvas.GetTop(sender))
    End Sub

    Private Sub thumb_Loaded(sender As Object, e As RoutedEventArgs)
        Dim t As Thumb = sender
        Dim bmp As BitmapImage = GetBitmapImage(t.Tag) 'Tagプロパティから取得した画像ファイルのパスから画像作成
        '取得したいコントロールの名前を指定してテンプレートの中から取得
        'テンプレートの中のコントロールを取得するTemplate.FindName
        Dim img As Image = t.Template.FindName("image1", t) 'テンプレートの中のコントロール取得
        img.Source = bmp
    End Sub


    Private Sub MainWindow_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop
        'ドロップされたファイルのパスを取得
        Dim filesPath() As String = e.Data.GetData(DataFormats.FileDrop)
        'ファイルパスの画像を割り当てたImageコントロールをGridに表示
        Dim locate As New Point(0, 0) 'Thumbを表示する位置
        For i As Integer = 0 To filesPath.Length - 1
            Call AddThumb(filesPath(i), locate) 'Thumb作成表示
            locate.Offset(30, 30) '位置の変更
        Next
    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

    'ThumbControlを作成して追加
    Private Sub AddThumb(filesPath As String, locate As Point)
        Dim t As New Thumb
        canvas1.Children.Add(t)
        'Resourcesの中にある取得したいTemplateのKeyを指定してThumbのTemplateに指定する
        t.Template = Me.Resources.Item("ct")

        t.Tag = filesPath 'Tagプロパティに画像ファイルのパスを入れておく
        Canvas.SetLeft(t, locate.X) '表示する位置は必須、指定しないとDragdeltaイベントで移動量が取得できない
        Canvas.SetTop(t, locate.Y)  '必須

        '作成した直後の今のタイミングでテンプレートの中のコントロールを取得しようとするとうまくいかないので
        'Loaded(作成完了直後)の時に取得するようにLoadedイベント時のメソッドを指定する
        AddHandler t.Loaded, AddressOf thumb_Loaded
        AddHandler t.DragDelta, AddressOf Thumb_Dragdelta 'これはマウスドラッグ用

    End Sub
End Class
例外処理してないけど
画像ファイルドロップで表示した画像をマウスドラッグで移動できるようにした
 

    'ファイルパスからBitmapImage(画像)を作成して返す
    Private Function GetBitmapImage(filePath As String) As BitmapImage

f:id:gogowaten:20191025100154p:plain

これは前回の
WPFVBでアプリ作る準備その1、マウスドラッグでコントロールの移動 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13900213.html
この記事の時と同じかな
ファイルをロックしないようにfilestreamを使ってBitmapImageを作成

   
 'ドラッグ移動
    Private Sub Thumb_Dragdelta(sender As Object, e As DragDeltaEventArgs)

f:id:gogowaten:20191025100235p:plain

Thumbコントロールをマウスドラッグで移動する時用
他のコントロールよりラクに動かせるのがThumbコントロール

 
ドロップされたパスをすべて取得する
    Private Sub MainWindow_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop

f:id:gogowaten:20191025100302p:plain

これも前回の記事と同じかな違うのはImageを作るのがThumbに変わったところ
28行目の
Call AddThumb(filesPath(i), locate) 'Thumb作成表示

 
 
 
Thumbコントロールを作成してCanvasに追加する
Private Sub AddThumb(filesPath As String, locate As Point)

f:id:gogowaten:20191025100317p:plain

53行目、Resources.Item("ct")
ctというKeyを持ったControlTemplateを取得すると同時に
これをt(Thumb)のTemplateに指定している
 
あとはTemplateの中のImageを取得して画像を指定したいけど
作成完了してからじゃないとできないみたいなので
Loadedイベントでするようにしているのが61行目の
        AddHandler t.Loaded, AddressOf thumb_Loaded
ここで困ったのがLoadedイベントの時にどうやって画像ファイルのパス取得するか
いろいろ方法はあるけど、今回は作成したThumbのTagプロパティに持たせることにしたのが55行目
        t.Tag = filesPath 'Tagプロパティに画像ファイルのパスを入れておく
 
ここが終わるとLoadedイベントが発生する

 
    Private Sub thumb_Loaded(sender As Object, e As RoutedEventArgs)

f:id:gogowaten:20191025100330p:plain

ThumbができあがったらLoadedイベントが発生するのでここで画像を読み込んで指定する
画像取得はGetBitmapImageメソッドに投げる、この時必要なファイルパスはTagプロパティに入れておいたものを使っているのが14行目
        Dim bmp As BitmapImage = GetBitmapImage(t.Tag) 
 
(Thumb(t)のTemplateの中のControlを取得するには
Template.FindNameに取得したいControlの名前を指定する
今回取得したいImageにはimage1という名前を付けておいたので
17行目の
t.Template.FindName("image1", t)
これで取得できている
あとは取得したImage(img)のSourceプロパティに画像をしてすれば全て完了

 
今回もいろいろ新しいのを使った
デザイン画面のXAMLでは
Window.Resources
ControlTemplate
VBのコードでは
Resources.Item
 
一番難しかったのがControlTemplateの中のControlを取得する
Template.FindName
動的に作成しているControlが作成完了した後なら使えるけど
作成している途中では使えないってのがわからなくて諦めかけてたところに
片鱗懐古のブログ: wpf : TemplateからNameを元にコントロールを探す
http://pieceofnostalgy.blogspot.jp/2012/05/wpf-templatename.html
どうやらインスタンス化してからじゃないとできないみたい
よくわかんないけど見よう見まねでなんとかなった次第
 
 
イメージ 12
画像ファイルドロップして
表示された画像をマウスドラッグしているところ
イメージ 13
こういう普通っぽい画像でgif動画を作ると簡単に1MBを超えちゃうんだよねえ
上のgif動画は0.2MB
 
予定しているテスト、上の3つは必要な機能
  • 表示画像すべてを画像ファイルとして保存
  • ドラッグ移動時に指定ピクセルごとに移動
  • 表示画像のレイヤー間の移動(入れ替え)ZOrder指定
  • 指定した色を透明にする
  • レイアウト
 
完了したテスト
  • 画像ファイルドロップで画像表示
  • 画像をマウスドラッグで移動
全然進んでいないように見えるw
 
 
 
参照したところ
[C#] WPFのThumbコントロールを使ってドラッグを実装する | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/3701
M'sLabo report: コードで生成したコントロールに静的リソースを適用する方法
http://mslaboratory.blog.eonet.jp/default/2012/11/post-4482.html
片鱗懐古のブログ: wpf : TemplateからNameを元にコントロールを探す
http://pieceofnostalgy.blogspot.jp/2012/05/wpf-templatename.html

WPF_test3 (master) - Visual Studio Team Services
https://gogowaten.visualstudio.com/DefaultCollection/WPF/_git/WPF_test3?path=%2F&version=GBmaster&_a=contents
コードはここにおいてみた、自分以外でも見えるかな
Wpf_test53_コントロールテンプレートの中のコントロール取得
ってのが今回のもの
Gitってのは便利らしいけど使い方がわからなくてただのファイル置き場みたいになっているw

 
 
 
WPFVBでアプリ作る準備その3、ImageコントロールにDragDeltaイベントがほしくて擬似DragDelta ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/13911101.html
 
2016年5月21日追記
関連記事

gogowaten.hatenablog.com 

WPFVB.NET、ControlTemplateをコードで作成 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
http://blogs.yahoo.co.jp/gogowaten/14156250.html
 
2016年5月22日追記

gogowaten.hatenablog.com

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