views:

785

answers:

6

Hi

When opening a window, I register a Deleted-event-handler on my business object. It is passed to the constructor as business:

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

Now the user can click a button to delete it (removing the record, you know). The event handler is registered to capture deletion by other editor windows and notifying the user ("Item has been deleted in another editor window.").

If the user deletes it in the current window, this message would be stupid, so I'd like to unregister the event before:

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

My problem is simple: The message is displayed anyway, so unregistering does not work. I tried storing the EventHandler in a separate member. Does not work either.

Any help would be cool.

Matthias

P.S. Reading this post, I'm afraid that properly unregistering the event could make it unregistered for all editor windows. Could be the next problem. ;-)

A: 

From the few lines that I see, this could be the problem:

Business business = (Business)businessBindingSource.DataSource;

It looks like you are changing the reference held by business to a different object. Perhaps yours was only an example though and you are using the same object each time.

Ed Swangren
A: 

It's not clear where the business_Deleted method is. Is it in your window class, and is it an instance method? If so, the delegate is associated with that window (and only that window). Removing the handler should be fine.

Could you post a short but complete program that demonstrates the problem?

Jon Skeet
A: 

Hi

Of course, here is the shortest possible complete sample:

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();
        }
    }
}

I think it should be the same instance, Ed. Am I right with this?

Greets, and thanks to you!

Matthias

Mudu
Sorry to be a pain, but that's not complete. It doesn't have the Business class, and the designer part is missing. For GUIs, it's easier to hand-code short but complete examples IME. See http://pobox.com/~skeet/csharp/complete.html for the kind of thing I'm after. (Continued)
Jon Skeet
Having said that, assuming the binding source hasn't changed, it *should* work (and you don't need the businessDeletedHandler variable - just use business.Deleted += business_Deleted and business.Deleted -= business_Deleted.
Jon Skeet
A: 

If you realy want this behaviour ( I don't think, this is good pattern, bud its not matter ), you can derive from EventArgs class and add property for author of deletion. Then you can do:

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();
    }
}

or you can do it thiw way:

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;
    }
}
TcKs
Thank you, I'll have a closer look at it today. Why don't you think this behavior is a good pattern?
Mudu
Because if you have opened a lot of windows where is used this business obejct, user got a lot of messageboxes "Item has been deleted". It will propabldy confusing for user.Maybe the closing windows automaticly can be for user confusing too.
TcKs
At all, the situation "user want update business object, but business object is already deleted" you need resolve also in multi-user enviroment. I think, resolution this situation is enough. Because the this situation is only subset of "business object is already deleted".
TcKs
+1  A: 

I'm not sure why your sample code does not work as expected but you could try adding a private member variable to check if this user is deleting the record or another user.

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 */
}
Y Low
A: 

Could the event be registered more than once? I would put a break point after the

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.

SwDevMan81