2009-05-06 17 views
16

Zamierzam odpowiedzieć na moje własne pytanie tutaj, ponieważ spędziłem kilka godzin składając to razem i chciałem podzielić się tym, co znalazłem w nadziei, że ocalę kogoś innego do kopania.Jak hostować zawartość WPF w aplikacjach MFC?

Jest tam MSDN Walkthrough, który zabierze Cię tam najbardziej, ale jest kilka kluczowych elementów, które znalazłem gdzie indziej. Na przykład w instrukcji powiemy, aby umieścić linię [System :: STAThreadAttribute] przed definicją _tWinMain(), ale jeśli implementujesz standardową aplikację MFC, nie masz _tWinMain() w kodzie źródłowym.

Jeśli cokolwiek tutaj jest niejasne, nie krępuj się zadawać pytania, a ja zredaguję odpowiedź, aby wyjaśnić sprawę.

Odpowiedz

22

Krok 1: Skonfiguruj aplikację MFC skompilować ze wsparciem CLR

Najlepszym sposobem osiągnięcia interoperacyjności między macierzystym C++ i zarządzanego kodu .NET jest skompilować aplikację jako zarządzanego C++ zamiast macierzystym C++. Odbywa się to poprzez przejście do Właściwości konfiguracyjnych projektu. Pod General jest dostępna opcja "Wspólne środowisko uruchomieniowe". Ustaw tę opcję na "Wspólne środowisko uruchomieniowe/Clr".

Krok 2: Dodaj zespoły WPF do projektu

prawym przyciskiem myszy na projekcie w Solution Explorer i wybierz „Referencje”. Kliknij "Dodaj nowy punkt odniesienia". Na karcie .NET dodaj WindowsBase, PresentationCore, PresentationFramework i System. Upewnij się, że odbudujesz wszystko po dodaniu jakichkolwiek odniesień, aby je odebrać.

Krok 3: Ustaw STAThreadAttribute na aplikacji MFC

WPF wymaga STAThreadAttribute być ustawione na głównym wątku UI. Ustaw to, przechodząc do Właściwości konfiguracji projektu. Pod Linker-> Advanced znajduje się opcja o nazwie "atrybut wątku CLR". Ustaw to na "atrybut gwintowania STA".

Krok 4: Tworzenie instancji HwndSource zawinąć komponent WPF

System :: Okna :: Interop :: HwndSource jest klasa .NET, który obsługuje interakcji między MFC i .NET komponentów. Utworzyć stosując następującą składnię:

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; 

dodać zmienną składową HWND do klasy dialogowym, a następnie przypisać je tak: m_hWnd = (HWND) source-> Handle.ToPointer();

Obiekt źródłowy i powiązana z nim zawartość WPF pozostaną aktywne do czasu wywołania :: DestroyWindow (m_hWnd).

Krok 5: Dodaj kontroli WPF do owijarki HwndSource

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

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

Krok 6: Trzymać odniesienie do obiektu WPF

Ponieważ zmienna przeglądarki będą wychodzić z zakresu po wychodzimy z funkcji tworzenia, musimy jakoś odwołać się do niej.Zarządzane obiekty nie mogą być członkami niezarządzanych obiektów, ale można użyć szablonu otoki o nazwie gcroot, aby wykonać zadanie.

Dodaj zmienną składową do klasy dialogowym:

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

następnie dodaj następującą linię kodu w Krok 5:

m_webBrowser = browser; 

Teraz możemy uzyskać dostęp do właściwości i metod na składnik WPF przez m_webBrowser.

+0

bardzo ładne. dzięki za publikację. – Gishu

+1

source-> SizeToContent = System :: Windows :: SizeToContent :: WidthAndHeight; Tego właśnie mi brakowało! +1 –

+2

Dodatkowa informacja, jeśli nie ustawisz StaThreadModel, zawiesi się dość tajemniczo głęboko w MFC. I musisz ustawić model wątku w głównej aplikacji wykonywalnej. Jeśli ty, tak jak ja, miałbyś okno dialogowe, które chcesz zastąpić w innej bibliotece DLL, to ** nie ** pomoże, jeśli ustawisz atrybut wątku CLR na uncluded DLL. Może to być oczywiste dla innych, ale nie dla mnie. – Dervall