WPF UNITY雙向通訊

來源:互聯網
上載者:User
說明

需求是這樣的 —— 一個編輯器。既能夠方便得編輯各種待用資料表(Excel),又能夠對錶中指定的資源進行預覽(Spine骨骼動畫)。

問題在於適合做表編輯器的軟體架構,如WPF、Winform等等,都沒有相應的Spine渲染庫;而支援Spine渲染的架構,如、MonoGame、Cocos2D等,又或存在Excel庫不好用或者缺少軟體向控制項的問題。

我們採取的方案是,使用WPF做它擅長的軟體功能,而使用Unity作為“渲染控制項”。 技術路線

為什麼不用WPF嵌入?
將Unity嵌入WPF(或Winform),比較常見的做法是通過ActiveX將UnityWebPlayer封裝成一個真正的控制項。但由於UnityWebPlayer運行在安全沙箱中,它至少有以下兩個問題: 沒有System.IO的程式集,只能夠載入assetbundle,無法載入未經管線預先處理的Spine 沒法載入Excel檔案 如何將Unity Windows Standalone 嵌入WPF
將Standalone作為一個控制項,指定到WPF父視窗下。採用WindowsAPI來實現。

如何?Standalone與WPF雙向通訊
需要能在WPF中設定Standalone的當前Spine,也要能在Standalone上操作由WPF維護的Excel。一個可行的方案是pipes。
這篇討論中說Unity不初始化NamedPipelineServer。那麼就拿它當NamedPipelineClient好了。 將Unity Windows Standalone 嵌入WPF

核心代碼如下:
// 定義一個WPF使用者控制項,來定義Standalone的尺寸
ProcessStartInfo info = new ProcessStartInfo(“UnityControl.exe”);
info.UseShellExecute = true;
info.WindowStyle = ProcessWindowStyle.Minimized;
m_AppProcess = System.Diagnostics.Process.Start(info);
m_AppProcess.WaitForInputIdle();
this.Dispatcher.BeginInvoke(
System.Windows.Threading.DispatcherPriority.ApplicationIdle,
appIdleEvent, this, null);

// Application Idle 事件處理WindowInteropHelper helper = new WindowInteropHelper(Window.GetWindow(this));IntPtr ptr = helper.Handle;SetParent(app.MainWindowHandle, helper.Handle);SetWindowLong(new HandleRef(this, app.MainWindowHandle), GWL_STYLE, WS_VISIBLE);MoveWindow(app.MainWindowHandle, (int)control.Margin.Left, (int)control.Margin.Top, (int)control.Width, (int)control.Height, true);
實現Unity Windows Standalone與WPF通訊
// WPFNamedPipeServerStream pipeServer = new NamedPipeServerStream(    "testpipe",     PipeDirection.InOut,     1);pipeServer.WaitForConnection();string str = "hello from server!";byte[] outBuffer = Encoding.Unicode.GetBytes(str);int len = outBuffer.Length;pipeServer.WriteByte((byte)(len / 256));pipeServer.WriteByte((byte)(len % 256));pipeServer.Write(outBuffer, 0, len);pipeServer.Flush();len = pipeServer.ReadByte() * 256;len += pipeServer.ReadByte();byte[] inBuffer = new byte[len];pipeServer.Read(inBuffer, 0, len);string remoteInfo = Encoding.Unicode.GetString(inBuffer);lbRemoteInfo.Content = remoteInfo;// Unity pipeClient = new NamedPipeClientStream(    ".", "testpipe",     PipeDirection.InOut);pipeClient.Connect(10000);int len = pipeClient.ReadByte() * 256;len += pipeClient.ReadByte();byte[] inBuffer = new byte[len];pipeClient.Read(inBuffer, 0, len);remoteInfo = Encoding.Unicode.GetString(inBuffer);pipeClient.Flush();string str = "hello from client!";byte[] outBuffer = Encoding.Unicode.GetBytes(str);len = outBuffer.Length;pipeClient.WriteByte((byte)(len / 256));pipeClient.WriteByte((byte)(len % 256));pipeClient.Write(outBuffer, 0, len);pipeClient.Flush();
效果

做了一個簡單的測試,看上去效果不錯: Unity(Client)被嵌入WPF(Server)視窗 WPF向Unity發送一條”hello from server!”,在Unity控制項的左上方顯示 Unity向WPF發送一條”hello from client!”,顯示在一個WPF的Label上

說明和參考

MSDN管道通訊Demo
如何:使用具名管道進行網路處理序間通訊

Mono不支援管道安全層級
不用就可以了,NamedPipeServerStream建構函式裡,不要填TokenImpersonationLevel
StackOverflow

Unity無法啟動NamedPipelineServer
StackOverflow

在Unity中啟用System.IO.Pipes命名空間
在Player Settings中,將.net版本設定為.net2.0,預設是.net2.0 subset
StackOverflow

如何將表單嵌入為控制項
C#自訂控制項:WinForm將其它應用程式表單嵌入自己內部 unity的外掛程式winform

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.