2016-05-30 3 views
0

У меня есть этот код:Как правильно сбросить пользовательские события в C#?

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 =, но это не позволит. Итак, каков правильный способ для меня перехватить обработчик событий и не в конечном итоге вызвать оба набора кода? Неужели я ошибаюсь?

спасибо.

ответ

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; 
+0

Спасибо. Я попробую это утром. –

+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; 
+0

Если он не проходит его как лямбда, он должен быть в состоянии отказаться от подписки делегата используя - =. – bodangly

+0

Но разве это не первая лямбда, которую ему нужно удалить? Если я не ошибаюсь, он хочет очистить свой собственный обработчик, который совершенно кошерный. – bodangly

+0

Если я сначала загружаю, а затем я использую mru, то нагрузка будет вызвана для обоих. Это фактически тот же обработчик, но я должен определить его в обоих событиях меню, потому что я не могу поместить код в конструктор формы. –

1

Поэтому в основном + = является синтаксический сахар для вызова Комбинируйте на своем мероприятии. Делегаты хранятся в списке вызовов, а поведение по умолчанию при запуске события - для каждого делегата в списке вызовов, чтобы получить вызов в том порядке, в котором они были добавлены. Вот почему вы не можете просто установить OnLoadingCompleted для одного делегата с помощью знака = - событие хранит список делегатов, а не один.

Вы можете удалить делегат с - = (синтаксический сахар для вызова Remove). Возможно, вы хотите официально объявить предыдущий делегат где-то, а не передавать его как лямбда. Это позволит вам удалить его, когда вы закончите с ним.

+0

На самом деле это не то, что вы не можете назначить ему вообще. Фактически вы * можете * назначать событие из класса, который его определяет. Вы не можете назначать событие извне определения этого класса, потому что концепция события заключается в том, что один потребитель может повлиять на другого потребителя события. * * Дизайн * * * * * *. – Servy

+1

@Servy Все, что я объяснял, это то, зачем ему нужно использовать + =. Может быть, мой ответ был неясным или я вас неправильно понял? Обработчики сохраняются в списке. – bodangly

+0

@bodangly Я понимаю, что вы говорите. И это будет способ сделать это (прежде объявить функцию события). Я дам вам голосование за ваш вклад, но я принял один из других ответов. Благодарю. –

1

Вы можете удалить обработчик, если это именованная функция:

private void OnLoadingComplete_AddFile(_sender, _e) 
{ 
    mruMenu.AddFile(dlgFile.FileName); 
    m_sUITInfo.dbDatabase = m_oThreadServices.GetDatabase(); 
    CreateView(); 
} 

... 

m_oThreadServices.OnLoadingCompleted += OnLoadingComplete_AddFile; 

... 

m_oThreadServices.OnLoadingCompleted -= OnLoadingComplete_AddFile; 

Удаление обработчика, который не был добавлен (или уже удален) является не-оп, так что вы можете просто удалить «другой» обработчик, прежде чем добавить его: это обеспечит наличие не более одного обработчика.

+0

Спасибо за предложение. Теперь я могу видеть, что я мог бы объявить две отдельные функции и удалить по мере необходимости. Тем не менее, я выполнил один из других ответов и отметил его. Но я дам вам голос. :) –

Смежные вопросы