在C ++ / CLI中使用Typecasting EventHandler

时间:2018-03-15 18:00:51

标签: casting c++-cli eventhandler

我有一个嵌入TabControl的表单(我称之为MainForm)。每次用户创建一个新选项卡时,它都会填充一个预构建面板的实例(我将调用MyPanel),其中包含许多控件。

我的MyPanel类有一个私有变量bool save_state,每当编辑一个(可编辑的)控件时设置为false,并在用户"时设置为true。节省"小组的状态。

我想要一个可视标记来跟踪未保存更改的标签(例如标签" Tab1"将显示文本" Tab1 *"如果有未保存的更改) 。所以我想在我的MainForm中设置事件处理程序,它可以在MyPanel中调用一个方法来为每个控件添加处理程序。

由于并非我的所有控件都使用相同的EventHandler类型(例如,我还需要跟踪DataGridViewRowsAddedEvent等),我目前有几种方法将相应的处理程序添加到相应的控件(每种类型的事件处理程序一个,每个都运行相同的代码(即将save_state位设置为false并将" *"附加到选项卡文本。

例如,在MainForm.cpp我有:

#include "MyPanel.h"

void markUnsaved(void) {
  // set panel bit to false
  // append " *" to tab text if we haven't already
}

void MainForm::handler1(Object ^sender, EventArgs ^e) {
  markUnsaved();
}

void MainForm::handler2(Object ^sender, DataGridViewRowsAddedEventArgs ^e) {
  markUnsaved();
}

void Main::FormaddNewPanelToTab(int tab_index) {
  // check index is valid ...


  // make the new panel
  MyPanel ^new_panel = gcnew MyPanel();
  new_panel->addEventHandlerToControls(gcnew EventHandler(this, &MainForm::handler1));
  new_panel->addDgvEventHandlerToControls(gcnew DataGridViewRowsAddedEventHandler(this, &MainForm::handler2));

  // rest of code...
}

虽然目前按预期工作,但这(以及我必须管理的其他几个事件处理程序类型)使我的代码看起来很傻。

我希望能够在MainForm中使用单个事件处理程序,并在MyPanel中使用单个方法对类型转换传递的事件处理程序,并将其添加到具有相应的所有控件中类型。

我尝试过简单的演员表,例如:

void MyPanel::addHandlerToControls(EventHandler ^handler) {
  control_NUD->ValueChanged += handler; // this works because ValueChanged is of type EventHandler
  control_DGV->RowsAdded += (DataGridViewRowsAddedEventHandler ^)handler; // this compiles but throws an exception

  // rest of the code...
}

无济于事。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

我知道回答可能有点迟,但我想说明如何解决这个问题。

我建议首先摆脱构建事件处理程序的想法。这种方法可以在C#中进行(通过一些调整)但据我所知,C++ /CLI中无法实现。

我会去为MyPanel类添加新事件,每次更改面板上的数据时都会调用该事件。但是为了避免向MyPanel类中的控件事件添加许多不同的处理程序,最好创建一个通用方法来处理所有必要控件的事件并触发新事件。也许这听起来很混乱,让我展示代码:

public ref class MyPanel 
{
    // Add a new event
    public: 
        event EventHandler^ DataChanged;

    // Add a method that will fire new event 
    // this methid will be invoked on every control's event that you'll subscribe
    private: 
        generic <typename T>
        void DataChangedHandler(System::Object^ sender, T e)
        {
            // Fire the event
            DataChanged(this, EventArgs::Empty);
        }

    // Once the controls are initialized you may add the event handlers
    // I put it in a constructor only for example
    MyPanel()
    {
        control_NUD->ValueChanged += gcnew EventHandler(this, &MyPanel::DataChangedHandler<EventArgs^>);
        control_DGV->RowsAdded += gcnew DataGridViewRowsAddedEventHandler(this, &MyPanel::DataChangedHandler<DataGridViewRowsAddedEventArgs^>);
        // and so on...
    }
}


/// And now in a main form we only need to subscribe to a DataChanged event
public ref class MainForm
{
    //...

    // the handler
    void MyHandler(Object^ sender, EventArgs^ e) 
    {
        markUnsaved();
    }

    void FormaddNewPanelToTab(int tab_index) 
    {
        // make the new panel
        MyPanel ^new_panel = gcnew MyPanel();
        new_panel->DataChanged += gcnew EventHandler(this, &MainForm::MyHandler);
    }

    //...
}

希望这有帮助。