Отмена регистрации события с оператором - = -

При открытии окна я регистрирую обработчик события Deleted-event в своем бизнес-объекте. Он передается конструктору как business:

business.Deleted += new EventHandler<EventArgs>(business_Deleted);

Теперь пользователь может нажать кнопку, чтобы удалить его (вы знаете, удаление записи). Обработчик событий зарегистрирован для захвата удаления другими окнами редактора и уведомления пользователя («Элемент был удален в другом окне редактора.»).

Если пользователь удалит его в текущем окне, это сообщение будет глупым, поэтому я бы хотел отменить регистрацию события раньше:

Business business = (Business)businessBindingSource.DataSource;
business.Deleted -= new EventHandler<EventArgs>(business_Deleted);

Моя проблема проста: сообщение все равно отображается, поэтому отмена регистрации не работает. Я попытался сохранить EventHandler в отдельном члене. Тоже не работает.

Любая помощь была бы крутой.

Матиас

P.S. Читая эта почта, я боюсь, что правильная отмена регистрации события может сделать его незарегистрированным для всех окон редактора. Может быть следующая проблема. ;-)

Непонятно, где находится метод business_Deleted. Находится ли он в вашем классе окна и является ли это методом экземпляра? Если да, то делегат связан с этим окном (и только с этим окном). Удаление обработчика должно быть нормальным. Не могли бы вы опубликовать короткую, но полную программу, демонстрирующую проблему?

Jon Skeet 20.11.2008 11:16
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
2 125
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Судя по нескольким строкам, которые я вижу, это может быть проблемой:

Business business = (Business)businessBindingSource.DataSource;

Похоже, вы меняете ссылку, которую держит бизнес, на другой объект. Возможно, ваш был лишь примером, и вы каждый раз используете один и тот же объект.

Конечно, вот кратчайший полный образец:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication
{
    public partial class BusinessEditor : Form
    {
        private EventHandler<EventArgs> businessDeletedHandler;

        public BusinessEditor(Business business)
            : this()
        {
            InitializeComponent();

            businessBindingSource.DataSource = business;

            // Registering
            businessDeletedHandler = new EventHandler<EventArgs>(business_Deleted);
            business.Deleted += businessDeletedHandler;
        }

        void business_Deleted(object sender, EventArgs e)
        {
            MessageBox.Show("Item has been deleted in another editor window.",
                "...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            Close();
        }

        private void deleteButton_Activate(object sender, EventArgs e)
        {
            Business c = (Business)businessBindingSource.DataSource;
            // Unregistering
            c.Deleted -= businessDeletedHandler;
            c.Delete();
            Close();
        }
    }
}

Думаю, это должен быть тот же случай, Эд. Я прав в этом?

Приветствую и спасибо вам!

Извините за боль, но это еще не все. В нем нет бизнес-класса, отсутствует дизайнерская часть. Для графических интерфейсов проще вручную написать короткие, но полные примеры IME. См. pobox.com/~skeet/csharp/complete.html для того, что мне нужно. (Продолжение)

Jon Skeet 20.11.2008 11:47

Сказав это, при условии, что источник привязки не изменился, должен работает (и вам не нужна переменная businessDeletedHandler - просто используйте business.Deleted + = business_Deleted и business.Deleted - = business_Deleted.

Jon Skeet 20.11.2008 11:49
Ответ принят как подходящий

Если вам действительно нужно такое поведение (я не думаю, что это хороший шаблон, но это не имеет значения), вы можете унаследовать от класса EventArgs и добавить свойство для автора удаления. Тогда вы сможете:

c.Delete( this ); //this = window
// ...
void business_Deleted(object sender, EventArgs e) {
    bool isDeletedFromMe = false;
    if ( e is DeletedEventArgs ) { isDeletedFromMe = object.ReferenceEquals( this, e.Author ); }
    if ( false == isDeletedFromMe ) {
        MessageBox.Show("Item has been deleted in another editor window.",
            "...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
        Close();
    }
}

или вы можете сделать это так:

void business_Deleted(object sender, EventArgs e)
{
    if ( false == object.ReferenceEquals( sender, this.currentlyDeletingBusiness ) ) {
        MessageBox.Show("Item has been deleted in another editor window.",
            "...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
    }
    Close();
}

Business currentlyDeletingBusiness;
private void deleteButton_Activate(object sender, EventArgs e)
{
    Business c = (Business)businessBindingSource.DataSource;
    try {
        this.currentlyDeletingBusiness = c;
        c.Delete();
    }
    finally {
        this.currentlyDeletingBusiness = null;
    }
}

Спасибо, сегодня посмотрю повнимательнее. Почему вы не думаете, что такое поведение - хороший образец?

Matthias Meid 20.11.2008 13:24

Потому что, если вы открыли много окон, в которых используется этот бизнес-объект, у пользователя появилось много ящиков сообщений «Элемент был удален». Это может сбить с толку пользователя. Возможно, автоматическое закрытие окон тоже может сбить с толку пользователя.

TcKs 20.11.2008 13:40

Вообще, ситуацию «пользователь хочет обновить бизнес-объект, но бизнес-объект уже удален» нужно разрешать также в многопользовательской среде. Думаю, разрешения этой ситуации достаточно. Потому что это только подмножество «бизнес-объект уже удален».

TcKs 20.11.2008 13:44

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

private bool otherUser = true;

void business_Deleted(object sender, EventArgs e)
{
    if (otherUser) {
        /* Show message */
    }
}

void deleteButton_Activate(object sender, EventArgs e)
{
    otherUser = false;
    /* Delete record */
}

Можно ли зарегистрировать мероприятие более одного раза? Я бы поставил точку останова после

business.Deleted -= new EventHandler(business_Deleted);
and check the _invocationCount and _invocationList of business.Deleted (under Base -> Non-Public members) to make sure there are no more events registered.

Другие вопросы по теме