2010-10-06 9 views
5

Nella mia applicazione WPF, il contenuto Win32 viene ospitato tramite HwndHost. Tuttavia, la creazione di un HwndHost non crea la finestra nativa. Piuttosto, questo viene fatto nel metodo BuildWindowCore() sovrascritto che viene chiamato qualche tempo dopo da WPF.Forzare l'inizializzazione di un HwndHost

mio contenuti ospitati bisogno del handle di finestra della finestra nativa per la propria inizializzazione. Sfortunatamente, non è possibile forzare la creazione della finestra (cioè avendo WPF chiamare BuildWindowCore), quindi ho un secondo thread che esegue il polling di HwndHost fino a quando non è stato inizializzato.

In .NET 4.0/WPF 4.0, è stato aggiunto un nuovo metodo WindowInteropHelper.EnsureHandle(). Speravo che questo avrebbe risolto la situazione, ma funziona solo per una finestra, non un HwndHost (che non deriva da Window). Hai un suggerimento cosa potrei fare invece?

EDIT:

ho dimenticato di aggiungere un po 'più vincoli per una possibile soluzione:

  1. Il HwndHost è posto in un controllo che, a seconda delle impostazioni utente, può essere un figlio della richiesta del principale finestra o può essere inserito in una nuova finestra (tramite un gestore di attracco di terze parti). Ciò significa che durante la creazione della finestra non so per certo quale sarà la finestra padre (e quindi la sua hWnd).
  2. Mentre il codice nativo necessita di hWnd durante l'inizializzazione, la finestra viene visualizzata solo quando l'utente richiede di visualizzarla (ad esempio, all'inizio è invisibile). Se è necessario mostrare la finestra, solo per nasconderlo immediatamente di nuovo, dovrebbe essere evitato.

risposta

3

Sembra che non ci sia una soluzione perfetta. Ho cambiato leggermente il mio approccio rispetto al momento della domanda:

Nel costruttore della mia classe derivata da HwndHost ho il (possibile) genitore hWnd come uno dei parametri. Quindi creo la finestra nativa utilizzando il metodo nativo CreateWindow(), utilizzando il dato genitore hWnd. Conservo l'hWnd creato in una proprietà separata, che utilizzo ovunque invece della proprietà Handle di HwndHost. In questo modo, non ho bisogno di mostrare la finestra (questo risolve il vincolo # 2).

Nel metodo BuildWindowCore() sottoposto a override, confronto il dato genitore hWnd con quello che ho ricevuto nel costruttore. Se sono diversi, ho riparato la mia finestra ospitata usando il metodo nativo SetParent() (questo risolve il vincolo # 1). Si noti che ciò non dipende da nessuno che memorizzi il genitore hWnd!

Nel codice, le parti pertinenti (controlli omessi):

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

Ho una situazione simile e ho risolto facendo quanto segue:

1) Creare una classe derivata HwndHost che prende un Rect come argomento del costruttore (poi utilizzato in BuildWindowCore):

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

2) Creare una finestra WPF con un elemento Border bambino:

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

3) Creare l'istanza HwndHost e aggiungerlo al th e la finestra nel gestore Window_Loaded:

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

4) Anche nel gestore Window_Loaded, passare il HWND per l'inizializzazione della classe nativa tramite P/Invoke o C++/CLI. Ho la mia classe nativa impostata per utilizzare quell'HWND come genitore e crea il suo HWND da bambino.

+0

Esistono due problemi: 1) Non conosco il padre hWnd, poiché il controllo viene successivamente posizionato da un gestore di attracco di terze parti e le impostazioni utente memorizzate determinano se viene visualizzato da solo o come " figlio "della finestra principale. 2) Il controllo con HwndHost potrebbe non essere mostrato inizialmente (a seconda delle impostazioni dell'utente memorizzato), ma all'avvio il codice legacy necessita di hWnd. –

+0

Dovresti essere in grado di collegarti all'evento Loaded sul tuo controllo e fare tutto l'inizializzazione lì: http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.loaded.aspx. Se il codice legacy ha bisogno dell'hwnd, allora devi solo continuare a fare qualsiasi cosa con il codice legacy fino a quando hwnd è pronto (che è quello che dovevo fare). –

+0

Citazione dal link: "Si verifica quando l'elemento è disposto, reso e pronto per l'interazione." Se non mostro il controllo, Loaded non sparerà. –

0

Un po 'in ritardo, ma hai provato a chiamare UpdateLayout() sul controllo di hosting? Questo ha funzionato per me

+0

Sfortunatamente, questo funziona solo se il controllo di hosting è visibile. Questo è esattamente il problema risolto da ConfirmHandle(), ma non esiste per HwndHosts. –

0

ho aggiunto l'evento OnHandleCreated alla mia HwndHost classe -inherited, che contiene l'IntPtr maniglia. Questo evento è invocato all'interno di BuildWindowCore().

Così tutto si riduce a:

public class Win32WindowHost : HwndHost { ... }

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

funziona a meraviglia.

+0

Sfortunatamente, questo non funziona nel mio caso. BuildWindowCore() viene richiamato solo quando viene mostrato HwndHost. Non c'è altro modo per forzare la creazione dell'hwnd nativo (cioè forzare WPF a chiamare BuildWindowCore()). Questo è possibile solo per qualcosa derivato da Window, tramite WindowInteropHelper.EnsureHandle(). –

Problemi correlati