2010-10-06 132 views
5

在我的WPF應用程序中,我使用HwndHost託管Win32內容。但是,創建HwndHost不會創建本機窗口。相反,這是在覆蓋的BuildWindowCore()方法中完成的,WPF將在稍後調用該方法。強制初始化HwndHost

我的託管內容需要本機窗口的窗口句柄進行自己的初始化。不幸的是,我不能強制創建窗口(即讓WPF調用BuildWindowCore),所以我有第二個線程輪詢HwndHost直到它被初始化。

在.NET 4.0/WPF 4.0中,增加了一種新方法WindowInteropHelper.EnsureHandle()。我希望這可以解決這種情況,但它只適用於Window,而不是HwndHost(它不是Window派生的)。你有什麼我可以做的建議嗎?

編輯:

忘了添加一些更多的約束的可能的解決方案:

  1. 的HwndHost被放置在一個控制其中,取決於用戶設置,可以是應用程序的主的子窗口或可以放置在新窗口中(通過第三方對接管理器)。這意味着在創建窗口時我不確定父窗口(以及它的hWnd)是什麼。
  2. 儘管本機代碼在其初始化過程中需要hWnd,但只有在用戶請求顯示該窗口時纔會顯示該窗口(即它最初不可見)。如果可能,應該避免需要顯示窗口,只能立即再次隱藏窗口。

回答

3

似乎沒有完美的解決方案。與被問到的問題時間相比,我略微改變了方法:

在我的HwndHost派生類的構造函數中,我有(可能的)父hWnd作爲參數之一。然後我使用給定的父hWnd使用本地CreateWindow()方法創建本地窗口。我將創建的hWnd存儲在一個單獨的屬性中,我使用它來代替HwndHost的Handle屬性。這樣,我不需要顯示窗口(這解決了約束#2)。

在重寫的BuildWindowCore()方法中,我將給定的父hWnd與我在構造函數中給出的父hWnd進行比較。如果它們不同,我使用原生SetParent()方法(這解決了約束#1)重新託管我的託管窗口。請注意,這依賴於沒有人存儲父HWWD!

在代碼中,相關部分(省略檢查):

public class Win32Window : HwndHost 
{ 
    public Win32Window(IntPtr parentHwnd) 
    { 
     this.ParentHwnd = parentHwnd; 
     this.Win32Handle = NativeMethods.CreateWindowEx(/* parameters omitted*/); 
    } 

    public IntPtr Win32Handle { get; private set; } 
    private IntPtr ParentHwnd { get; set; } 

    protected override HandleRef BuildWindowCore(HandleRef hwndParent) 
    { 
     if (hwndParent.Handle != this.ParentHwnd) 
     { 
      NativeMethods.SetParent(this.Win32Handle, hwndParent.Handle); 
     } 

     return new HandleRef(this, this.Win32Handle); 
    } 
} 
1

我有類似的情況,我這樣做解決了下列文件:

1)創建一個HwndHost派生類需要一個矩形作爲一個構造函數的參數(後來在BuildWindowCore使用):

public class MyHwndHost : HwndHost 
{ 
    public MyHwndHost(Rect boundingBox) 
    { 
     BoundingBox = boundingBox; 
    } 
} 

2)創建一個WPF窗口與孩子Border元素:

<Window Loaded="Window_Loaded"> 
    <Border Name="HostElement" /> 
</Window> 

3)創建HwndHost實例,並把它添加到TH在Window_Loaded處理機Ê窗口:

void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    MyHwndHost host = new MyHwndHost(LayoutInformation.GetLayoutSlot(HostElement)); 
    HostElement.Child = host; 
} 

4)另外,在處理程序Window_Loaded,通過HWND到原生類的既可以通過P /調用或C++/CLI的初始化。我有我的母語課程設置爲使用該HWND作爲其父母,並創建自己的HWND作爲孩子。

+0

有兩個問題:1)我不知道父hWnd,因爲控件後來由第三方對接管理器定位,並且存儲的用戶設置確定它是自己顯示還是作爲「孩子「的主窗口。 2)HwndHost的控制最初可能不會顯示(取決於存儲的用戶設置),但在啓動時,舊代碼需要hWnd。 – 2011-06-24 08:26:22

+0

您應該可以掛鉤到控件上的Loaded事件,並在其中進行所有初始化:http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.loaded.aspx。如果遺留代碼需要hwnd,那麼你只需要在遺留代碼上做任何事情,直到hwnd準備就緒(這是我必須做的)。 – 2011-06-27 14:12:06

+0

來自鏈接的引用:「當元素佈局,呈現並準備好進行交互時發生。」如果我沒有顯示控件,Loaded將不會觸發。 – 2011-06-28 07:09:17

0

有點遲了,但你有沒有試過在主機控制上調用UpdateLayout()?這對我有用

+0

不幸的是,這隻有在宿主控件可見的情況下才有效。這正是EnsureHandle()解決的問題,但HwndHosts不存在。 – 2011-06-24 08:27:28

0

我添加一個事件OnHandleCreated到我HwndHost -inherited類,它包含手柄的IntPtr。此事件在BuildWindowCore()內調用。

所以它歸結爲:

public class Win32WindowHost : HwndHost { ... }

var host = new Win32WindowHost(); 
host.OnHandleCreated += (sender, e) => 
{ 
    var handle = e.Handle; 
    // Do stuff. 
}; 

作品一種享受。

+0

不幸的是,這在我的情況下不起作用。只有在顯示HwndHost時才調用BuildWindowCore()。沒有其他辦法可以強制創建本地hwnd(即強制WPF調用BuildWindowCore())。這隻能通過WindowInteropHelper.EnsureHandle()從窗口派生出來。 – 2014-02-19 15:02:03