如何在C#中正确重置自定义事件?

时间:2016-05-30 20:55:19

标签: c# winforms custom-events

我有这段代码:

private void loadGENIOFileToolStripMenuItem_Click(object sender, EventArgs e)
{
    OpenFileDialog dlgFile = new OpenFileDialog();

    dlgFile.InitialDirectory = Properties.Settings.Default.PreviousPath;
    dlgFile.Title = "Select GENIO file";
    dlgFile.Filter = "GENIO files (*.txt)|*.txt";
    dlgFile.FilterIndex = 0;
    dlgFile.Multiselect = false;

    if (dlgFile.ShowDialog() == DialogResult.OK)
    {
        Properties.Settings.Default.PreviousPath = Path.GetDirectoryName(dlgFile.FileName);

        DeleteView();

        m_oThreadServices.OnLoadingCompleted += (_sender, _e) =>
        {
            mruMenu.AddFile(dlgFile.FileName);
            m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
            CreateView();
        };

        m_oThreadServices.SetGenioFilePath(dlgFile.FileName);
        m_oThreadServices.start();
    }
}

但我也在尝试实现一个MRU处理程序:

    private void OnMruFile(int number, String filename)
    {
        if (File.Exists(filename))
        {
            Properties.Settings.Default.PreviousPath = Path.GetDirectoryName(filename);

            DeleteView();

            m_oThreadServices.OnLoadingCompleted += (_sender, _e) =>
            {
                mruMenu.SetFirstFile(number);
                m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
                CreateView();
            };

            m_oThreadServices.SetGenioFilePath(filename);
            m_oThreadServices.start();
        }
        else
            mruMenu.RemoveFile(number);
    }
}

我的m_oThreadServices.OnLoadingCompleted代码行似乎要求我使用+ =,因此,如果我首先加载文件,它会添加第一个事件处理程序。如果我然后使用 MRU 列表加载其他文件,则最终会运行两个 OnLoadingCompleted 处理程序。

我尝试了m_oThreadServices.OnLoadingCompleted =,但不允许这样做。那么,拦截事件处理程序并最终调用两组代码的正确方法是什么?我错了吗?

谢谢。

4 个答案:

答案 0 :(得分:1)

没有直接从处理程序中删除匿名或未知事件的方法。但是,您可以在MSDN上查看此论坛帖子:https://social.msdn.microsoft.com/Forums/vstudio/en-US/45071852-3a61-4181-9a25-068a8698b8b6/how-do-i-determine-if-an-event-has-a-handler-already?forum=netfxbcl

有一些关于使用反射从事件处理程序中删除委托的代码和讨论。

虽然要明白你想要完成什么可能会更好。也许有更好的方法来获得您正在寻找的最终结果而不是重新连接事件。

删除已建立的事件代码以更改要实现的代码的行为通常不是一种好习惯。它可能导致意想不到的后果和不稳定的行为。如果定义了事件代码,那么最好保持它就位并围绕它设计应用程序。

另一方面,如果这是由您或代码库添加的代码,则可以将其删除,如果您已经进行了适当的研究以验证其删除并且不会导致应用程序在其他地方中断。最好的方法是将事件代码放在命名函数中:

public void MyEventCode(object sender, EventArgs args)
{
   // Do event stuff..
}

然后您可以按名称删除事件:

control.DoMyEvent -= MyEventCode;

答案 1 :(得分:1)

所以基本上+ =是在你的事件上调用Combine的语法糖。委托存储在调用列表中,触发事件时的默认行为是调用列表中的每个委托按添加顺序调用。这就是为什么你不能简单地将OnLoadingCompleted设置为一个带有=符号的委托 - 一个事件存储一个委托列表,而不是一个。

您可以使用 - =(用于调用Remove的语法糖)删除委托。也许你想在某个地方正式声明前一个委托,而不是把它作为一个lambda传递。这可以让你在完成它后删除它。

答案 2 :(得分:1)

如果处理程序是命名函数,则可以删除它:

<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<nav class="navbar navbar-default navbar-fixed-top">
  <div class="container-fluid">
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#main_navbar">
        <span class="fa fa-bars"></span>
      </button>
      <a class="navbar-brand" href="#">Navbar</a>
    </div>
    <div class="collapse navbar-collapse" id="main_navbar">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Menu 1</a>
        </li>
        <li><a href="#">Menu 2</a>
        </li>
        <li><a href="#">Menu 3</a>
        </li>
      </ul>
    </div>
  </div>
</nav>

删除尚未添加(或已被删除)的处理程序是无操作,因此您只需删除&#34;其他&#34;添加一个之前的处理程序:这将确保最多只有一个处理程序。

答案 3 :(得分:1)

一旦引发事件,您应确保从事件源中取消订阅事件处理程序。

为了做到这一点,你必须修改一下匿名处理程序。例如,这个片段:

m_oThreadServices.OnLoadingCompleted += (_sender, _e) =>
{
    mruMenu.AddFile(dlgFile.FileName);
    m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
    CreateView();
};

应该是这样的:

EventHandler onLoadingCompleted = null;
onLoadingCompleted = (_sender, _e) =>
{
    m_oThreadServices.OnLoadingCompleted -= onLoadingCompleted;
    mruMenu.AddFile(dlgFile.FileName);
    m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase();
    CreateView();
};
m_oThreadServices.OnLoadingCompleted += onLoadingCompleted;

另一个相同。

该行

EventHandler onLoadingCompleted = null;
需要

以避免在此使用未初始化的变量编译器错误

m_oThreadServices.OnLoadingCompleted -= onLoadingCompleted;