2009-05-06 6 views
16

Je vais répondre à ma propre question ici parce que j'ai passé quelques heures à la reconstituer et j'ai voulu partager ce que j'ai trouvé dans l'espoir de sauver quelqu'un d'autre.Comment héberger le contenu WPF dans les applications MFC?

Il y a un MSDN Walkthrough qui vous donne le plus de chemin, mais il y a quelques pièces clés que j'ai trouvées ailleurs. Par exemple, la procédure pas à pas vous demande de placer la ligne [System :: STAThreadAttribute] avant la définition de _tWinMain() mais si vous implémentez une application MFC standard, vous n'avez pas _tWinMain() dans votre code source.

Si quelque chose ici n'est pas clair, n'hésitez pas à poser des questions et je vais modifier la réponse pour clarifier les choses.

Répondre

22

Étape 1: Configurer l'application MFC pour compiler avec le support CLR

La meilleure façon de réaliser l'interopérabilité entre C++ natif et le code managé .NET est de compiler l'application comme géré C++ plutôt que C++ natif. Ceci est fait en allant dans les propriétés de configuration du projet. Sous Général, il y a une option "Common Language Runtime support". Réglez ceci sur "Common Language Runtime Support/clr".

Étape 2: Ajouter les ensembles de WPF au projet

Faites un clic droit sur le projet dans la solution Explorer et choisissez « Références ». Cliquez sur "Ajouter une nouvelle référence". Sous l'onglet .NET, ajoutez WindowsBase, PresentationCore, PresentationFramework et System. Assurez-vous de reconstruire tout après avoir ajouté des références afin qu'elles soient récupérées.

Étape 3: Définir STAThreadAttribute sur l'application MFC

WPF exige que STAThreadAttribute être réglé sur le thread principal de l'interface utilisateur. Définissez ceci en allant dans Propriétés de configuration du projet. Sous Linker-> Advanced, il y a une option appelée "CLR Thread Attribute". Définissez ceci sur "Attribut de thread STA".

Étape 4: Créer une instance de HwndSource pour envelopper le composant WPF

System :: :: Interop de Windows :: HwndSource est une classe .NET qui gère l'interaction entre les composants MFC et .NET. Créer une en utilisant la syntaxe suivante:

System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew  System::Windows::Interop::HwndSourceParameters("MyWindowName"); 
sourceParams->PositionX = x; 
sourceParams->PositionY = y; 
sourceParams->ParentWindow = System::IntPtr(hWndParent); 
sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD; 

System::Windows::Interop::HwndSource^ source = gcnew System::Windows::Interop::HwndSource(*sourceParams); 
source->SizeToContent = System::Windows::SizeToContent::WidthAndHeight; 

Ajouter une variable membre HWND à la classe de dialogue puis attribuez-lui comme ceci: m_hWnd = (HWND) source-> Handle.ToPointer();

L'objet source et le contenu WPF associé resteront présents jusqu'à ce que vous appeliez :: DestroyWindow (m_hWnd).

Étape 5: Ajoutez le contrôle WPF à l'enveloppe HwndSource

System::Windows::Controls::WebBrowser^ browser = gcnew System::Windows::Controls::WebBrowser(); 

browser->Height = height; 
browser->Width = width; 
source->RootVisual = browser; 

Étape 6: Gardez une référence à l'objet WPF

Depuis la variable du navigateur se sont hors de portée après nous quittons la fonction en faisant la création, nous devons en quelque sorte tenir une référence à celle-ci.Les objets gérés ne peuvent pas être membres d'objets non gérés, mais vous pouvez utiliser un modèle de wrapper appelé gcroot pour effectuer le travail.

Ajouter une variable membre à la classe de dialogue:

#include <vcclr.h> 
gcroot<System::Windows::Controls::WebBrowser^> m_webBrowser; 

Ensuite, ajoutez la ligne suivante au code à l'étape 5:

m_webBrowser = browser; 

Maintenant, nous pouvons accéder aux propriétés et méthodes sur le composant WPF à travers m_webBrowser.

+0

très agréable. Merci d'avoir posté. – Gishu

+1

source-> SizeToContent = Système :: Windows :: SizeToContent :: WidthAndHeight; C'était ce qui me manquait! +1 –

+2

Une information supplémentaire, si vous ne définissez pas le StaThreadModel, il va planter mystérieusement profondément dans MFC. Et vous devez définir le modèle de thread sur l'application exécutable principale. Si vous, comme moi, avez la boîte de dialogue que vous voulez remplacer dans une autre DLL, cela ne sera pas ** utile si vous définissez l'attribut de thread CLR sur la DLL non cliquée. Cela pourrait être évident pour les autres, mais ce n'était pas à moi. – Dervall

Questions connexes