При открытии окна я регистрирую обработчик события 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 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 для того, что мне нужно. (Продолжение)
Сказав это, при условии, что источник привязки не изменился, должен работает (и вам не нужна переменная businessDeletedHandler - просто используйте business.Deleted + = business_Deleted и business.Deleted - = business_Deleted.
Если вам действительно нужно такое поведение (я не думаю, что это хороший шаблон, но это не имеет значения), вы можете унаследовать от класса 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;
}
}
Спасибо, сегодня посмотрю повнимательнее. Почему вы не думаете, что такое поведение - хороший образец?
Потому что, если вы открыли много окон, в которых используется этот бизнес-объект, у пользователя появилось много ящиков сообщений «Элемент был удален». Это может сбить с толку пользователя. Возможно, автоматическое закрытие окон тоже может сбить с толку пользователя.
Вообще, ситуацию «пользователь хочет обновить бизнес-объект, но бизнес-объект уже удален» нужно разрешать также в многопользовательской среде. Думаю, разрешения этой ситуации достаточно. Потому что это только подмножество «бизнес-объект уже удален».
Я не уверен, почему ваш пример кода не работает должным образом, но вы можете попробовать добавить частную переменную-член, чтобы проверить, удаляет ли этот пользователь запись или другой пользователь.
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.
Непонятно, где находится метод business_Deleted. Находится ли он в вашем классе окна и является ли это методом экземпляра? Если да, то делегат связан с этим окном (и только с этим окном). Удаление обработчика должно быть нормальным. Не могли бы вы опубликовать короткую, но полную программу, демонстрирующую проблему?