将matlab弹出的figure嵌入wpf窗体中

我开始做这个调查的时候老是抓着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;

到此一个简单的嵌入就完成了。