由於幾個星期,我們試圖「改造」一個MFC對話框爲「MFC形式」,它可以被嵌入到一個WinForm用戶控件。
我們已經成功地做到這一點:
- 我們做了一個WinForm用戶控件,叫做Dlg_WU_MFC_Container
- 在創建時,UC創建MFC形式稱爲CDlgEdgeType
- 然後,每次UC調整大小或移動時,我們也會移動並調整MFC窗體的大小
下面是代碼(I試圖刪除了許多不必要的東西..):
Dlg_WU_MFC_Container.h:
#pragma once
public ref class Dlg_WU_MFC_Container : public System::Windows::Forms::UserControl
{
private:
CDlgEdgeType* _dialog;
CWnd *_wnd;
private: //---Local Controls
System::ComponentModel::IContainer^ components;
public:
Dlg_WU_MFC_Container();
~Dlg_WU_MFC_Container();
!Dlg_WU_MFC_Container();
template<class T, class HP>
void InitializeContainer() {
CDlgEdgeType =
}
private:
void RefreshEmbeddedSize();
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->SuspendLayout();
//
// Dlg_WU_MFC_Container
//
this->AutoScaleDimensions = System::Drawing::SizeF(96, 96);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Dpi;
this->ForeColor = System::Drawing::SystemColors::WindowText;
this->Margin = System::Windows::Forms::Padding(0);
this->Name = L"Dlg_WU_MFC_Container";
this->Size = System::Drawing::Size(816, 480);
this->SizeChanged += gcnew System::EventHandler(this, &Dlg_WU_MFC_Container::evSizeChanged);
this->VisibleChanged += gcnew System::EventHandler(this, &Dlg_WU_MFC_Container::evVisibleChanged);
this->ResumeLayout(false);
}
#pragma endregion
private: System::Void evSizeChanged(System::Object^ sender, System::EventArgs^ e);
private: System::Void evVisibleChanged(System::Object^ sender, System::EventArgs^ e);
};
Dlg_WU_MFC_Container.cpp:
#include "Dlg_WU_MFC_Container.h"
#include "DlgEdgeType.h"
Dlg_WU_MFC_Container::Dlg_WU_MFC_Container()
{
InitializeComponent();
_wnd = NULL;
_dialog = new CDlgEdgeType();
}
Dlg_WU_MFC_Container::~Dlg_WU_MFC_Container()
{
if (components)
{
delete components;
}
this->!Dlg_WU_MFC_Container();
}
Dlg_WU_MFC_Container::!Dlg_WU_MFC_Container()
{
// We need to detach the handle to free it for other usage
if (_wnd) {
_wnd->Detach();
delete _wnd;
_wnd = NULL;
}
if (_dialog) {
delete _dialog;
_dialog = NULL;
}
}
System::Void Dlg_WU_MFC_Container::evSizeChanged(System::Object^ sender, System::EventArgs^ e) {
RefreshEmbeddedSize();
}
// Inform the embedded form to adapt to its new size
void Dlg_WU_MFC_Container::RefreshEmbeddedSize() {
if (_dialog && _isShown) {
CRect containerWnd;
containerWnd.left = this->Left;
containerWnd.right = this->Right;
containerWnd.top = this->Top;
containerWnd.bottom = this->Bottom;
_dialog->ReplaceEmbeddedForm(containerWnd);
}
}
System::Void Dlg_WU_MFC_Container::evVisibleChanged(System::Object^ sender, System::EventArgs^ e) {
// _isShown basically useless.. !
if (Visible != _isShown) {
_isShown = Visible;
if (_dialog) {
if (Visible) {
void *handle = Handle.ToPointer();
if (handle) {
// We need to create a new CWnd which will contain
// the handle of the current WinForm control where
// the embedded MFC will be contained
_wnd = new CWnd();
_wnd->Attach((HWND)handle);
_dialog->Create(_wnd);
RefreshEmbeddedSize();
}
} else {
// When the control is not shown anymore, we need to free
// the handle so another control can use it (the handle
// is stored in the MFC permanent map)
_wnd->Detach();
_dialog->DestroyWindow();
delete _wnd;
_wnd = NULL;
}
}
}
}
CDlgEdgeType.cpp:
void CDlgEdgeType::ReplaceEmbeddedForm(CRect &rect) {
if (!GetSafeHwnd()) {
return;
}
SetWindowPos(NULL, rect.left, rect.top, rect.Width(), rect.Height(), SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER);
}
這東西工作「很好」:CDlgEdgeType很好地顯示在我們的應用程序中,當應用程序調整大小或移動時,一切都很順利。
這裏是我的問題: CDlgEdgeType有Dlg_WU_MFC_Container父,偉大的。但是後者不知道MFC窗體是一個「小孩」..所以焦點有點丟失,箭頭鍵和Tab鍵根本不起作用。
你應該知道的事情是,Dlg_WU_MFC_Container添加到的TabPages定製的TabControl的。因此,如果用戶試圖通過MFC窗體的控件導航,或者他試圖通過箭頭鍵瀏覽TreeView,則TabControl似乎將接管焦點並將更改選項卡..這不方便D:
I我的同事們都不知道如何解決這個問題。也許我們整合MFC的方式是錯誤的,但是沒有真正的關於這個的話題(我們看到更多的「將WinForm表單嵌入到MFC中......」)。另外,由於我們的軟件歷史悠久,我們不能簡單地重新創建CDlgEdgeType。這是一個很大的對話框,事實上,我們有7個類似的對話框,代碼實現了模板,但爲了清晰的顯示此信息,我刪除了它們。
謝謝!
Sbizz。
這只是一個非常基本的問題,只要你混合GUI框架就會發生。鍵盤快捷鍵處理由消息循環完成,並且您的程序中有錯誤的處理。 MFC循環不知道有關Winforms行爲的任何信息。曾經有一篇關於它的知識庫文章,但我找不到它。也許,沒有人認爲使用ShowDialog()是一個很好的解決方法。 –