wpf --自定義控件的transeform

 WPF不可以對非WPF控件進行Transform操作,但是對於我們自定義的控件仍然可以曝露消息進行一些Transform 操作,Transform 一般來說就是Matrix的實現,對於Matrix我們先來做道題:

  已知圓心O(0,0) ,在座標軸上有一點P( x , y ), 逆時針旋轉OP a度,使得P點到P1(x1,y1),用x,y表示p1點的座標。

WPF自定義控件——使用Win32控件

  解:顯然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

WPF自定義控件——使用Win32控件

  圖片看不清楚?請點擊這裏查看原圖(大圖)。

   從以上你是感覺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傳送(這個做法不推薦)。

WPF自定義控件——使用Win32控件

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章