WPF不可以對非WPF控件進行Transform操作,但是對於我們自定義的控件仍然可以曝露消息進行一些Transform 操作,Transform 一般來說就是Matrix的實現,對於Matrix我們先來做道題:
已知圓心O(0,0) ,在座標軸上有一點P( x , y ), 逆時針旋轉OP a度,使得P點到P1(x1,y1),用x,y表示p1點的座標。
解:顯然P1 O等於 PO,作 X軸上任意一點M,假設我們的角MOP爲b度,又已知角P1OP爲a度。
那麼得
x1 = PO * COS(a+b)
y1= PO * SIN(a+b)
展開得
x1 = PO * COS(a) * COS(b) – PO * SIN(a) * SIN(b)
y1 = PO * SIN(a)* COS(b) + PO * COS(a) * SIN(b)
因爲
x = PO * COS(b)
y = PO * SIN(b)
代入上式得
x1 = x * COS(a) – y*SIN(a)
y1 = y*COS(a) + x*SIN(a)
如果你對三角函數忘的夠徹底的話請看
http://zh.wikipedia.org/w/index.php?title=三角函數&variant=zh-cn
用矩陣表示移動前的點
x1[1*x ,0*y]
y1[0*x ,1*y]
移動後轉變成了
x y
x1 [COS(a) , –SIN(a)]
y1 [COS(a) , SIN(a)]
當然我們可能還有偏移量,比如向正方向豎移2個單位,向正單位橫移1個單位,也就是做了個仿射變換
x1 [COS(a) , –SIN(a)]
y1 [COS(a) , SIN(a)]
z [ 1 , 2 ]
爲了變化方便所以還加了一列,這樣的話上面的平移我們還可以這樣得到
[1,0,0] * x1 [COS(a) , –SIN(a) ,0]
[0,1,0] * y1 [COS(a) , SIN(a) ,0]
[1,2,1] * z [0 , 0 ,1]
注意:矩陣的乘法中 A*B 不等於 B * A 。
http://zh.wikipedia.org/w/index.php?title=變換矩陣&variant=zh-cn#.E4.BB.BF.E5.B0.84.E5.8F.98.E6.8D.A2http://zh.wikipedia.org/w/index.php?title=矩陣&variant=zh-cn
從以上你是感覺Matrix就是一個點的變化麼,把圖像中的每個點都逆時針旋轉下,圖像就斜了,或許你可以模擬出WPF中的RotateTransform、ScaleTransform、SkewTransform、TranslateTransform 這些類的效果。
對於WPF中當前的Matrix可以這樣得到 Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
四.消息通知
知道了這些我們就可以把Matrix作爲參數發送個win32自定義畫圖讓其也一起旋轉,變化.對於非託管控件我們通常使用SendMessage來傳遞消息,這裏用winform來做例子。
這裏我們先來看下http://hi.baidu.com/cyap/blog/item/9aebca0f5e4c612c6159f300.html這個網頁對pinvoke中發送消息的一些使用說明;其中我們還要注意SendMessage中的第四個參數如果傳遞的是int,struct,string,byte類型就相對容易些;在Marshal中便有對應的函數讀取Marshal.PtrToStructure,Marshal.PtrToStringAuto處理,假如傳遞是類的話,先要序列化,轉化成2進制之後,因爲從指針中並不能知道到這個指針所申請的空間大小,所以需要一個結構體來保存這個2進制數據的指針,以及他的長度。
public struct CopyDataStruct
{
/// <summary>
/// 數據長度
/// </summary>
public int cbData;
/// <summary>
/// 數據首地址指針
/// </summary>
public IntPtr lpData;
}
private void SendMessage()
{
System.Drawing.Drawing2D.Matrix matrix = new System.Drawing.Drawing2D.Matrix();
BinaryFormatter formatter = new BinaryFormatter();
byte[] datas;
using (System.IO.MemoryStream mStream = new System.IO.MemoryStream())
{
formatter.Serialize(mStream, matrix);
datas = mStream.ToArray();
}
int length = datas.Length;
IntPtr ptr = Marshal.AllocHGlobal(length);
Marshal.Copy(datas, 0, ptr, length);
CopyDataStruct data = new CopyDataStruct();
data.cbData = length;
data.lpData = ptr;
SendMessage(hwndListBox, 700, 0, ref data);
Marshal.FreeHGlobal(ptr);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 700)
{
CopyDataStruct data = new CopyDataStruct();
data = (CopyDataStruct)m.GetLParam(data.GetType());
byte[] datas = new byte[data.cbData];
Marshal.Copy(data.lpData, datas, 0, data.cbData);
BinaryFormatter formatter = new BinaryFormatter();
using (System.IO.MemoryStream mStream = new System.IO.MemoryStream(datas))
{
//得到對象
object obj = formatter.Deserialize(mStream);
}
}
}
當然如果你感覺比較麻煩的話,也可以把這兩個值分別放在WParam和LParam傳送(這個做法不推薦)。