Невозможно отсоединить события фонового рабочего окна форм (C #) - PullRequest
3 голосов
/ 10 января 2012

Когда я пытаюсь отменить регистрацию событий, передавая delgates в качестве параметров в функцию, которая отцепляет их, они точно не отсоединяются.

    public void registerHandlers(RunWorkerCompleted backgroundWorker1_RunWorkerCompleted, DoWork backgroundWorker1_dowork, ProgressChanged backgroundWorker1_ProgressChanged)
    {
        this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
        this.backgroundWorker1.DoWork += backgroundWorker1_dowork;
        this.backgroundWorker1.ProgressChanged += backgroundWorker1_ProgressChanged;  
    }

    public void unregisterHandlers(RunWorkerCompleted backgroundWorker1_RunWorkerCompleted, DoWork backgroundWorker1_dowork, ProgressChanged backgroundWorker1_ProgressChanged)
    {
        this.backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;
        this.backgroundWorker1.DoWork -= backgroundWorker1_dowork;
        this.backgroundWorker1.ProgressChanged -= backgroundWorker1_ProgressChanged;  
    }

    private void buuton1_click(object sender, EventArgs e)
    {
        registerHandlers(this.worker1_RunWorkerCompleted, this.worker1_doWork, this.worker1_progressChangedHandler);
        this.backgroundWorker1.RunWorkerAsync();
    }

    private void buuton2_click(object sender, EventArgs e)
    {
        registerHandlers(this.worker2_RunWorkerCompleted, this.worker2_doWork, this.worker2_progressChangedHandler);
        this.backgroundWorker1.RunWorkerAsync();
    }

    // ..

    private void worker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        try
        {
            // ...
        }
        catch(Exception e)
        {
            // ..
        }
        finally
        {
            unregisterHandlers(this.worker1_RunWorkerCompleted, this.worker1_doWork, this.worker1_progressChangedHandler);    
        }
    }

Ответы [ 4 ]

3 голосов
/ 11 января 2012

Изменение:

this.backgroundWorker1.RunWorkerCompleted -= new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);

на:

this.backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;

Это ошибка в вашем коде.(И точно так же, два рядом с ним.)

Но, честно говоря, не ясно, что происходит.Если вы не вызовете BackgroundWorker с помощью команды RunWorkerAsync(); - она ​​не будет работать, даже если она подключена.Так что же вы видите, что происходит не раз?Это RunWorkerCompleted, который вызывается дважды, когда one BackgroundWorker заканчивается?

Если вы просто хотите сохранить BackgroundWorker, чтобы использовать его снова - вы нужно чтобы отменить регистрацию.Ничто не сработает, пока вы снова не позвоните RunWorkerAsync();, а затем - захотите зарегистрированных событий.

1 голос
/ 10 января 2012

Я предполагаю, что это потому, что вы создаете экземпляр нового делегата и пытаетесь удалить его. Тем не менее, этот делегат никогда не был добавлен к событию в первую очередь. При работе с событиями, где я хочу подключить / отключить, я использую сам метод. Так что в вашем случае я бы сделал что-то вроде:

// ...

// Hook up to event
this.backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;

// ...

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // Unhook from event
    this.backgroundWorker1.RunWorkerCompleted -= backgroundWorker1_RunWorkerCompleted;

    // ...
}

Примечание: под делегатом я имею в виду ваши экземпляры обработчика событий (т.е. new RunWorkerCompletedEventHandler(...)).

1 голос
/ 11 января 2012

Я решил добавить к этому еще один ответ, так как поток комментариев к предыдущему посту становится довольно длинным, и редактирование моего текущего ответа слишком сильно его расширит.

Я немного озадачен вашим кодом - я не знаю, изменили ли вы его с момента публикации или нет. У меня есть несколько замечаний по этому вопросу:

  1. Убедитесь, что при подключении / отключении обработчиков событий к / от событий, которые вы не вызываете new для делегата. Просто используйте название метода (как указано в ответе выше - см. Ниже).

  2. Если вы не используете registerHandlers(...) и unregisterHandlers(...) в других местах, то я не вижу необходимости передавать делегаты, особенно если методы находятся в одном классе с этими делегатами. Конечно, метод может позволять знать этих делегатов и добавлять / удалять их соответственно.

  3. Вы изначально заявили, что ваш метод backgroundWorker1_RunWorkerCompleted выполнялся более одного раза, даже после отсоединения от события. Из того, что я вижу в вашем отредактированном коде, это вполне правдоподобно, поскольку вы нигде не снимаете этот обработчик событий. Вместо этого вы открепляете обработчик workerCompleted. Кроме того, тот факт, что вы назвали локальную переменную (внутри unregisterHandlers(...)) для делегата RunWorkerCompleted так же, как и фактический метод, может вызвать путаницу для компилятора (я не уверен в этом, но это может показаться вероятным мне).

Итак, в свете этих моментов я бы изменил приведенный выше код на что-то более похожее на это:

private BackgroundWorker mBackgroundWorker; // Instantiated elsewhere

#region Registration

private void RegisterHandlers()
{
    // Hook up to the background worker events
    mBackgroundWorker.RunWorkerCompleted += mBackgroundWorker_RunWorkerCompleted;
    mBackgroundWorker.DoWork += mBackgroundWorker_DoWork;
    mBackgroundWorker.ProgressChanged += mBackgroundWorker_ProgressChanged;
}

private void UnregisterHandlers()
{
    // Unhook from the background worker events
    mBackgroundWorker.RunWorkerCompleted -= mBackgroundWorker_RunWorkerCompleted;
    mBackgroundWorker.DoWork -= mBackgroundWorker_DoWork;
    mBackgroundWorker.ProgressChanged -= mBackgroundWorker_ProgressChanged;
}

#endregion

#region Event Handlers

private void Button1_Click(object sender, EventArgs e)
{
    RegisterHandlers();

    // Start the background worker
    mBackgroundWorker.RunWorkerAsync();
}

private void mBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    try
    {
        // ...
    }
    finally
    {
        UnregisterHandlers();
    }
}

private void mBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    // ...
}

private void mBackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // ...
}

#endregion

Обратите внимание, что имена методов и переменных не совсем совпадают с вашими собственными, поэтому вам нужно быть осторожным, чтобы изменить их соответствующим образом. Однако, если вы внимательно посмотрите на то, как написан код, вы должны понять, что я имею в виду в отношении перехвата / открепления обработчиков событий.

Надеюсь, это поможет.

EDIT

Я написал небольшое тестовое приложение, чтобы вручную проверить вашу проблему, и, следуя изложенным мною пунктам, у меня нет проблем. Исходный код моего тестового приложения можно найти на PasteBin . Результаты, напечатанные в моем окне вывода в Visual Studio:

Worker 1: Do Work
Worker 1: Run Worker Completed
Worker 2: Do Work
Worker 2: Run Worker Completed
Worker 1: Do Work
Worker 1: Run Worker Completed
Worker 2: Do Work
Worker 2: Run Worker Completed

Приведенный выше вывод является результатом нажатия рабочих кнопок в последовательности: работник 1, работник 2, работник 1, работник 2.

РЕДАКТИРОВАТЬ 2

В ответ на вашу попытку управления обработчиками событий сгенерированного дизайнером BackgroundWorker; Я полагаю, что в вашем коде происходит следующее:

  1. Код, сгенерированный дизайнером WinForms, создает экземпляр backgroundWorker1.
  2. Код, сгенерированный дизайнером WinForms, перехватывает обработчики событий backgroundWorker1 (количество обработчиков: 1).
  3. Пользователь нажимает button1.
  4. Ваш код перехватывает обработчики событий на backgroundWorker1 (количество обработчиков: 2). Это то место, где вы собираетесь получить несколько зацепок.

Если это является тем, что происходит, то вы должны быть в состоянии запретить сгенерированному дизайнером коду перехватывать события, удаляя любые обработчики событий, указанные в части «События» таблицы свойств конструктора форм.

0 голосов
/ 10 января 2012

попытаться унаследовать от класса BackgroundWorker и реализовать интерфейс IDisposable на нем .. и попробовать отменить регистрацию события в методе Dispose ()

Привет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...