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传送(这个做法不推荐)。