前回の
WPFとVB.NET、アプリでの編集状態保存、名前を付けて保存、回転角度を指定する2つの方法 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログこれをPixtack紫陽花2ndに組み込もうとして少し躓いたのでメモ
http://blogs.yahoo.co.jp/gogowaten/14093723.html
期待通りに動いているところ
デザイン画面とXAML
VBコード
Imports System.ComponentModel
Class MainWindow
Private FocusBorder As Border '選択中のBorderを入れておく用
'Borderをクリックした時
Private Sub Border_Click(b As Border, e As RoutedEventArgs)
'StackPanelのDataContextを変更する
sPanel1.DataContext = b.DataContext
'選択中のBorderを変更する
FocusBorder = b
End Sub
''' <summary>
''' TransformGroupの中から指定したTransformを返す
''' </summary>
''' <param name="tGroup">RenderTransformとか指定</param>
''' <param name="tType">取得したいTransformの指定、RotateTransformとか</param>
''' <returns></returns>
Private Function GetTransform(tGroup As TransformGroup, tType As Type) As Transform
For Each c As Transform In tGroup.Children
If tType = c.GetType Then
Return c
Exit For
End If
Next
Return Nothing
End Function
'アプリの起動直後
Private Sub MainWindow_Initialized(sender As Object, e As EventArgs) Handles Me.Initialized
'Borderを作成してStackPanelに追加表示
For i As Integer = 0 To 1
'回転角度、拡大率、傾斜角度を同時に指定するのでTransformGroupを使う
Dim tg As New TransformGroup
tg.Children.Add(New RotateTransform)
tg.Children.Add(New ScaleTransform)
tg.Children.Add(New SkewTransform)
'Border作成
Dim b As New Border
With b
.Background = New SolidColorBrush(Colors.Tomato)
.Width = 50
.Height = 50
.Margin = New Thickness(20)
.RenderTransformOrigin = New Point(0.5, 0.5)
.RenderTransform = tg 'さっきのTransformGroupを指定
End With
'Bindingの設定
'RenderTransformの中からそれぞれのTransformを取得する
Dim ro As RotateTransform = GetTransform(tg, GetType(RotateTransform))
Dim sc As ScaleTransform = GetTransform(tg, GetType(ScaleTransform))
Dim sk As SkewTransform = GetTransform(tg, GetType(SkewTransform))
'回転角度
Dim bind As New Binding("Angle")
bind.Mode = BindingMode.TwoWay
BindingOperations.SetBinding(ro, RotateTransform.AngleProperty, bind)
'拡大率
bind = New Binding("ScaleX")
BindingOperations.SetBinding(sc, ScaleTransform.ScaleXProperty, bind)
'傾斜角度
bind = New Binding("SkewX")
BindingOperations.SetBinding(sk, SkewTransform.AngleXProperty, bind)
'TransformGroupに入っている順番がわかりきっているならTransformの取得は
'tg.Children.Item(0)とか決め打ちでもいいかも?
'BindingOperations.SetBinding(tg.Children.Item(0), RotateTransform.AngleProperty, bind)
'BindingOperations.SetBinding(tg.Children.Item(1), ScaleTransform.ScaleXProperty, bind)
'BindingOperations.SetBinding(tg.Children.Item(2), SkewTransform.AngleXProperty, bind)
sPanel1.Children.Add(b) 'BorderをStackPanelに追加表示
'SaveDataを作成してStackPanelとBorderのDataContextに指定
Dim sd As New SaveData With {.Angle = 0, .ScaleX = 1, .SkewX = 0}
sPanel1.DataContext = sd
b.DataContext = sd
'Borderをクリックした時
AddHandler b.MouseLeftButtonDown, AddressOf Border_Click
'選択中のBorder
FocusBorder = b
Next
End Sub
Private Sub bt1_Click(sender As Object, e As RoutedEventArgs) Handles bt1.Click
'選択中のBorderの回転角度を30にする
'BorderのRenderTransformの中のRotateTransformのAngleを直接変更する場合
'OK
'Dim ro As RotateTransform = GetTransform(FocusBorder.RenderTransform, GetType(RotateTransform))
'ro.Angle = 30
'BorderのDataContextに入れてあるSaveDataのAngleを変更する場合
'OK
Dim sd As SaveData = FocusBorder.DataContext
sd.Angle = 30
'以下失敗例
'BorderのRenderTransformにRotateTransformを指定する?場合
'無視される
'FocusBorder.RenderTransform.SetValue(RotateTransform.AngleProperty, 30.0R)
'BorderのRenderTransformに新しいRotateTransformを上書き
'バインディングが無効になってしまう
'FocusBorder.RenderTransform = New RotateTransform(30)
End Sub
End Class
<Serializable>
Public Class SaveData
Implements ComponentModel.INotifyPropertyChanged
<NonSerialized>
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub OnPropertyChanged(name As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(name))
End Sub
Private Property _ScaleX As Double
'拡大率横用
Public Property ScaleX As Double
Get
Return _ScaleX
End Get
Set(value As Double)
_ScaleX = value
Call OnPropertyChanged("ScaleX")
End Set
End Property
Private Property _SkewX As Double
'傾斜横用
Public Property SkewX As Double
Get
Return _SkewX
End Get
Set(value As Double)
_SkewX = value
Call OnPropertyChanged("SkewX")
End Set
End Property
Private Property _Angle As Double
'回転角度用
Public Property Angle As Double
Get
Return _Angle
End Get
Set(value As Double)
'0から360の間に収めてからSet
value = value Mod 360
If value < 0 Then
value += 360
End If
_Angle = value
Call OnPropertyChanged("Angle")
End Set
End Property
End Class
コントロールの変形で使いたいのが3つあって
RotateTransform回転角度、ScaleTransform拡大率、SkewTransform傾斜角度
どれか1つなら前回の方法でよかったみたいだけど、3つ同時だとできなかった
Imageコントロールの回転角度を30に変形する場合
前回の方法
Image.RenderTransform.SetValue(RotateTransform.AngleProperty, 30.0R)
改善した?今回の方法
Dim ro As RotateTransform = GetTransform(FocusBorder.RenderTransform, GetType(RotateTransform))
ro.Angle = 30
Private Function GetTransform(tGroup As TransformGroup, tType As Type) As Transform
Dim tg As TransformGroup = tGroup
For Each c As Transform In tg.Children
If tType = c.GetType Then
Return c
Exit For
End If
Next
Return Nothing
End Function
コントロールの変形の指定方法
回転角度だけを指定、30度の場合
Image.RenderTransform = New RotateTransform(30)
拡大率縦横だけを指定、縦横2倍の場合
Image.RenderTransform = New ScaleTransform(2, 2)
どれか1つならこんなふうに1行で済むけど、組み合わせるときはTransformGroupを使って
↓
回転角度と拡大率を指定
Dim tg As New TransformGroup
tg.Children.Add(New RotateTransform(30))
tg.Children.Add(New ScaleTransform(2, 2))
Image.RenderTransform = tg
こうなる、ここまでは良かったけど
前回の方法で回転角度を45に変更
Image.RenderTransform.SetValue(RotateTransform.AngleProperty, 45.0R)
これでいいのかと思ったら、これだと無視されて変更されない
どうやらTransformGroupの中にあるRotateTransformまで届いていないみたい
そこでFor Each~NextでTransformGroupの中からRotateTransformを取得して、それに直接指定するようにしたのが今回の方法
まともな方法がありそうだけど見つからなかった
For Each~Nextを使わないで取得する
TransformGroupに入っている順番は入れた時の順番みたいなので、さっきの例だと
tg.Children.Item(0)にRotateTransformに入っていて
tg.Children.Item(1)にScaleTransformが入っている
決め打ちみたいだけどこっちのほうがラクかも
これでなんとかなった
BindingやDataContextは設定が難しいけどあとが楽になる感じ
コード
Wpf_test105_変形TransformのBinding_Datacontext - Visual Studio Team Services
https://gogowaten.visualstudio.com/DefaultCollection/WPF/_git/WPF_test6?path=%2FWpf_test105_%E5%A4%89%E5%BD%A2Transform%E3%81%AEBinding_Datacontext&version=GBmaster&_a=contents
Pixtack紫陽花2ndの様子
SliderのValueChangedイベントで変形させていたのを、SliderとImageをBindingするようにしただけだから、見た目も動作も変わっていないw
でもコードも減ったし動きも軽くなったかも?
次は名前を付けて保存機能