我開始做這個調查的時候老是抓着matlab 、Figure嵌入c#窗體這些關鍵字,查出來的結果基本上都是提問等待解決的,后來再一想matlab的Figure也是一個Window啊,既然c#能讓它顯示出來,肯定也有方法給嵌進去,所以后來就換了思路直接調查c# wpf 將窗體嵌入窗體中等關鍵字,最后功夫不負有心人,讓我在MSDN找到一篇叫在 WPF 中承載 Win32 控件的演練,看這標題就知道肯定是我們需要的,從這次調查經驗也提醒了大家以后做技術調查的時候在小范圍調查不到結果時,可以宏觀的考慮一下這個問題,說不定答案就有了。接下來我簡單的給大家講講我的實現步驟吧。
第一步:
環境的配置,vs就不用說了,matlab開發環境得裝,並且必須是帶有matlab builder ne 的版本,我用的是matlab 7.11.0(R2010b)。
第二步:
創建一個matlab的一個myTest.m文件作為這次演練的測試文件。(.p文件也可以編譯成.net 組件)具體代碼如下:
function test(h,D) for x=-10:0.1:10, if x>D y=h; hold on; plot(x,y) elseif x<-D y=-h; hold on; plot(x,y) else y=h/(D*x); hold on; plot(x,y) end end
第三步:
打開matlab開發環境,點擊File->New->Deployment Project 在彈出的對話框里填好前兩項工程名及存放位置,第三項Target則是最關鍵的部分,選擇.Net Assembly。然后點擊確定。
第四步:
在剛才新建的工程里點擊[Add Class]起一個名,然后再在新建的class下面點擊[Add files]。將剛才新建的myTest.m文件加進來。然后點擊build按鈕。生成完之后,在此工程目錄下的一個叫distrib文件夾下面會生成一個以工程名命名的dll文件。
第五步:
新建一個wpf 應用程序,將剛才生成的dll文件引用進來,同時還需將matlab安裝目錄下的一個叫MWArray.dll文件引用進來,具體位置是C:\Program Files\MATLAB\R2010b\toolbox\dotnetbuilder\bin\win32\v2.0\MWArray.dll。引用完這兩個文件之后,我們就可以在wpf程序里調用matlab東西了。
第六步:
調用,代碼如下:
matTest.Class1 test = new matTest.Class1(); MWArray m = 1, n = 2; test.test(m, n);
第七步:
從這步開始講將matlab的Figure嵌入wpf中了。
首先新建一個ControlHost類,此類必須繼承自HwndHost,並重寫它的BuildWindowCore方法。具體代碼如下:
public class ControlHost : HwndHost { // private const int WS_CHILD = 0x40000000; [DllImport("user32.dll")] private static extern int SetParent(IntPtr hWndChild, IntPtr hWndParent); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern uint SetWindowLong(IntPtr hwnd, int nIndex, uint newLong); [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] private static extern uint GetWindowLong(IntPtr hwnd, int nIndex); [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)] internal static extern bool DestroyWindow(IntPtr hwnd); IntPtr hwndControl; IntPtr hwndHost; int hostHeight, hostWidth; [System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow( string lpClassName, string lpWindowName ); public ControlHost(double height, double width) { hostHeight = (int)height; hostWidth = (int)width; } protected override HandleRef BuildWindowCore(HandleRef hwndParent) { hwndControl = IntPtr.Zero; hwndHost = IntPtr.Zero; matTest.Class1 test = new matTest.Class1(); MWArray m = 1, n = 2; test.test(m, n);
Thread.Sleep(1000); hwndControl = FindWindow(null, "Figure 1");//Figure 1 是彈出的Figure的名字
uint oldStyle = GetWindowLong(hwndControl, GWL_STYLE); SetWindowLong(hwndControl, GWL_STYLE, (WS_DLGFRAME | WS_CHILD)); // WS_DLGFRAME 是創建一個無標題的窗口 //將 嵌入的Figure的父窗口設置為HwndHost SetParent(hwndControl, hwndParent.Handle); return new HandleRef(this, hwndControl); } protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { handled = false; return IntPtr.Zero; } protected override void DestroyWindowCore(HandleRef hwnd) { DestroyWindow(hwnd.Handle); } public IntPtr hwndListBox { get { return hwndControl; } } internal const int WS_CHILD = 0x40000000, WS_VISIBLE = 0x10000000, LBS_NOTIFY = 0x00000001, HOST_ID = 0x00000002, LISTBOX_ID = 0x00000001, WS_VSCROLL = 0x00200000, WS_BORDER = 0x00800000, GWL_STYLE = -16, WS_DLGFRAME = 0x00400000; }
第八步:
在主窗體中添加一個Borde標簽起名HostElement。並給此Border定好寬高,在此此寬高決定了要嵌進來的窗體的寬高。然后在主窗體的load事件寫下如下代碼:
ControlHost listControl = new ControlHost(); HostElement.Child = listControl;
到此一個簡單的嵌入就完成了。