本文介绍了C ++ / CLI:将MFC嵌入WinForm的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,

几个星期以来,我们试图将MFC对话框转换为可以嵌入到WinForm用户控件中的 MFC表单 。

Since a few weeks, we are trying to "transform" a MFC dialog into a "MFC form" which can be embedded into a WinForm User Control.

我们成功做到了:


  • 我们制作了WinForm用户控件,称为 Dlg_WU_MFC_Container

  • 创建后,UC会创建名为 CDlgEdgeType

  • 然后,每次调整UC大小或移动UC时,我们也会移动并调整MFC表单的大小

下面是代码(试图删除很多不必要的东西..):

Here is the code (I tried to remove a lot of unnecessary stuff..):

Dlg_WU_MFC_Container.h:

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:

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:

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 可以很好地显示在我们的应用程序中,并且在调整应用程序大小或移动应用程序时,一切正常。

This stuff is working "great" : CDlgEdgeType is well shown in our application and when the application is resized or moved, everything goes well.

这是我的问题:
CDlgEdgeType 具有 Dlg_WU_MFC_Container 作为父级,太好了。但是后者不知道MFC表单是子级 ..因此焦点有点丢失,箭头键和Tab键根本不起作用。

Here is my issue:CDlgEdgeType has Dlg_WU_MFC_Container as parent, great. But the latter doesn't know that the MFC form is a "child".. so the focus is kind of lost and the Arrow keys and the Tab keys simply do not work.

您应该知道的是,已将 Dlg_WU_MFC_Container 添加到自定义 TabControl TabPages 中。因此,如果用户尝试通过MFC窗体的控件进行导航,或者他尝试使用方向键通过TreeView进行导航,则TabControl似乎将接管焦点并更改选项卡。.这不方便D:

A thing you should know is that Dlg_WU_MFC_Container is added to TabPages of a custom TabControl. So, if the user tries to navigate through MFC form's controls or he tries to navigate through a TreeView with the Arrow keys, the TabControl seems to take over the focus and will change tab.. which is not convenient D:

我也不知道如何解决这个问题,我的同事们也不知道。

I have no idea how to solve that issue, neither my colleagues.

也许我们集成MFC的方式是错误的,但是没有真正的话题(我们看到更多将WinForm表单嵌入MFC)。另外,由于我们的软件历史悠久,因此我们不能简单地重新创建CDlgEdgeType。这是一个很大的对话框,实际上,我们有7个这样的对话框,代码实现了模板,但是为了清楚起见,我删除了它们。.

Maybe the way we integrate the MFC is wrong, but there are no really topics about that (we see more "Embedding WinForm forms into MFC"..). Also, as our software has a big history, we cannot simply recreate CDlgEdgeType. It's a big dialog and, in fact, we have 7 dialogs like that, the code implements template but I removed them for the clarity of this message..

谢谢!

Sbizz。

推荐答案

好吧,我们找到了出路。

Well, we find a way out.. this may not be the best way to do it, but it is working (or at least, it seems to work !).

起初,我已经设法做到这一点。将键发送到MFC表单:

At first, I've managed to send the keys to the MFC form:

bool Dlg_WU_MFC_Container::ProcessDialogKey(Keys keyData) {
    ::SendMessage(CWnd::GetFocus()->GetSafeHwnd(), WM_KEYDOWN, (WPARAM)keyData, (LPARAM)0);

    return true;
}

由于TabControl正在通过WM_ACTIVATE进行控制,因此我们试图覆盖,同时将WM_ACTIVATE发送到MFC表单,因此结果如下:

Since the TabControl is taking the control through an WM_ACTIVATE, we tried to "override" it by sending also WM_ACTIVATE to the MFC form, so the result is the following:

bool Dlg_WU_MFC_Container::ProcessDialogKey(Keys keyData) {
    ::SendMessage(CWnd::GetFocus()->GetSafeHwnd(), WM_ACTIVATE, MAKEWPARAM(WA_ACTIVE, 0), (LPARAM)0);
    ::SendMessage(CWnd::GetFocus()->GetSafeHwnd(), WM_KEYDOWN, (WPARAM)keyData, (LPARAM)0);

    return true;
}

唯一的问题是 Tab键似乎不起作用但是经过调查,我们的用户并不需要它,所以...:D但是我认为它仅与WM_ACTIVATE(先前的控件)的第三个参数有关。必须使用它来知道在按下Tab后必须聚焦哪个控件。

The only thing is that the "Tab" key doesn't seems to work but after investigation, it is not needed by our users, so... :D But I think it's just related to the third parameter of WM_ACTIVATE (previous control). It must be used to know which control must be focused after Tab is pressed.

Sbizz

这篇关于C ++ / CLI:将MFC嵌入WinForm的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 07:23