How to Add an eventHandler only one time?

A

aplaxas

Hi!

"CDemo.Call" eventHandler is added to "button3.click"
Event when both button1 and button2 are clicked.
However, I want to add "cd.Call" only one time even though
I clicked both button1 and button2.

For Example,
1. Click button1
2. Click button2
3. Click button3
4. One MessageBox is shown

How to do this job?


private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.Button button3;

public CDemo cd = new CDemo();
..
private void button1_Click(object sender, System.EventArgs
e)
{
button3.Click += new EventHandler(cd.Call);
}

private void button2_Click(object sender, System.EventArgs
e)
{
button3.Click += new EventHandler(cd.Call);
}

..
..
..
public class CDemo
{
public void Call(object sender, System.EventArgs e)
{
MessageBox.Show("Demo");
}
}
 
M

Mattias Sjögren

private bool handlerAdded = false;

private void button1_Click(object sender, System.EventArgs e)
{
if ( !handlerAdded ) {
button3.Click += new EventHandler(cd.Call);
handlerAdded = true;
}
}

and similarly for button2_Click.



Mattias
 
J

Jongmin

Hi!

Even your code provides one solution, I can't use your
code.
I don't want use another global variable in order to solve
this situation.
I have to solve this problem only with both object
instance button3 and cd.

Thanks,
Jongmin
 
L

lukasz

how about this:

private void button1_Click(...) {
button3.Click -= new EventHandler(cd.Call);
button3.Click += new EventHandler(cd.Call);
}

private void button2_Click(...) {
button3.Click -= new EventHandler(cd.Call);
button3.Click += new EventHandler(cd.Call);
}

Keeps only one event handler.
 
G

Guest

Hi,

Why don't you enable button3 on button1 (or button2) click?
Has it any more functionality than cd.Call?

I don't want use another global variable in order to solve
this situation.

If code of your button handlers lies in a form class,
you shold not affraid to use any simple variables. They take
less memory than any of your control.

Previous solutions should be suitable too.

Regards

Marcin
 
J

Jongmin

The codesnippet just simplified my problem for explaining.

In real code, I have many kinds of object not window form
types.
 
J

Jongmin

Yes, I have used your way as the following code.

for(int intI=0; intI < 10; intI++)
button3.Click -= new EventHandler(cd.Call);

button3.Click += new EventHandler(cd.Call);

I thought this is so clumsy.
 
L

lukasz

Can you explain why you want such a strange behavior? Maybe you have wrong
approach to the problem.
 
J

Jongmin

Basically, I have four classes related to this situation,
TPart, TRefPart, TPartCollection, and TRefPartCollection.
TPart is basic type and holds data.
TRefPart is referring TPart instance. It means TRefPart
depends on TPart.
TPartCollection and TRefPartCollection is used for
DataBinding.

For Example,

TPart part = new TPart();
part.Idx = 1;
part.Name = "Hard Disk XXXXXXX";

TRefPart refPart1 = new TRefPart(part);
TRefPart refPart2 = new TRefPart();
refPart2.Idx = part.Idx;

TRefPartCollection refParts = new TRefPartCollection();
refParts.Add(refPart1);
refParts.Add(refpart2);

listBox.DataSource = refParts;
part.Name = "Hard Disk";
MessageBox.Show(refPart1); // -> "Hard Disk";
MessageBox.Show(refPart2); // -> "Hard Disk";

Even though both refPart1 and refPart2 show correct Name
of part1, this part.Name change can't refresh list of
ListBox fully, because refPart2's OnName_Changed
eventhandler is not added to Part's NameChange Event.

I have to add the following code after creating part2.
part.NameChanged = refPart2.OnName_Changed

My problem is this adding job takes places multifully at
differet area.

Thanks,
Jongmin




public class TPart
{
public event EventHandler NameChanged;

private int _Idx = 0;
public virtual int Idx
{
set { _Idx = value;}
get { return _Idx ;}
}

private string _Name = "Noname";
public string Name
{
set
{
_Name = value;
Name_Changed();

}
get { return _Name ;}
}
private void Name_Changed()
{
if (NameChanged != null)
NameChanged(this, System.EventArgs.Empty);
}
}


public class TRefPart
{
public event EventHandler NameChanged;

public TRefPart()
{
}

public TRefPart(TPart part)
{
this.Idx = part.Idx;
ConnectEventHandler(part);
}

public static TPart operator ~(TRefPart a)
{
/*
return the TPart which has same Idx in my
application.
*/
return null;
}

public string Name
{
get
{
if ((~this) != null)
return (~this).Name;
else
return "N/A";
}
}
private void ConnectEventHandler(TPart part)
{
if (part != null)
{
part.NameChanged +=new EventHandler
(OnName_Changed);
}

}
private void DisconnectEventHandler(TPart part)
{
if (part != null)
{
part.NameChanged -=new EventHandler
(OnName_Changed);
}
}

public override string ToString()
{
return Name;
}

public void OnName_Changed(object sender,
System.EventArgs e)
{
base.Name_Changed();
}
}

public class TRefPartCollection :CollectionBase,
IBindingList
{
public TPartCollection()
{
}

private ListChangedEventArgs resetEvent = new
ListChangedEventArgs(ListChangedType.Reset, -1);
public event ListChangedEventHandler ListChanged;
public event EventHandler RefPartAdded;
public event EventHandler RefPartRemoved;

..
..

protected override void OnInsertComplete(int index,
object value)
{
RefPart_Added((TRefPart)value);
OnListChanged(new ListChangedEventArgs
(ListChangedType.ItemAdded, index));
}

private void RefPart_Added(TRefPart item)
{
item.NameChanged += new EventHandler
(OnRefPartName_Changed);
}

private void OnRefPartName_Changed(object sender,
System.EventArgs e)
{
OnListChanged(resetEvent);
}
}

public class TPartCollection :CollectionBase, IBindingList
{
public TPartCollection()
{
}

private ListChangedEventArgs resetEvent = new
ListChangedEventArgs(ListChangedType.Reset, -1);
public event ListChangedEventHandler ListChanged;
public event EventHandler PartAdded;
public event EventHandler PartRemoved;

}
 
L

lukasz

TRefPart refPart1 = new TRefPart(part);
TRefPart refPart2 = new TRefPart();
refPart2.Idx = part.Idx;

Why not create refPart2 the same way as refPart1? If you have part.Idx, you
have part, so you can assign part's OnNameChanged.

Another option would be looking up the part object in TPartCollection and
once you get it, assign its OnNameChanged, all inside TRefPart.Idx setter.

public void OnName_Changed(object sender,
System.EventArgs e)
{
base.Name_Changed();
}

what's the base? Object?

Btw, what you present now is a bit different from what you asked about
previously.
 
J

Jongmin

Why not create refPart2 the same way as refPart1? If you have part.Idx, you
have part, so you can assign part's OnNameChanged.
This is example why I need to add EventHander to event
seperately.

Another option would be looking up the part object in TPartCollection and
once you get it, assign its OnNameChanged, all inside TRefPart.Idx setter.

public void OnName_Changed(object sender,
System.EventArgs e)
{
base.Name_Changed();
}

what's the base? Object?
It is my mistypo. It should be Name_Changed();
Btw, what you present now is a bit different from what you asked about
previously.
I know this code is totally differen from previous one.
But, I simplified my code for explaining.

Again, the problem is
bbbb.XXXXXXXX += new EventHandler(cccc.AAAAAA);

When I add a event handler of cccc to bbbb's event,
1. If the event handler(AAAAAA) has already been added
to the bbbbb's event(XXXXXXXX ), NOT ADD.

2. If the event handler(AAAAAA) has NOT, ADD cccc's
AAAA to bbbb.XXXXXXXX

Thanks,
Jongmin
 
L

lukasz

Another nasty suggestion (untested):

public delegate void XxxEventHandler();

....

private ArrayList delegates;

public void AddXxxDelegate(XxxEventHandler deleg) {
if (!delegates.Contains(deleg))
delegates.Add(deleg);
}

protected virtual void OnXxx() {
foreach (XxxEventHandler deleg in delegates)
deleg.DynamicInvoke(null);
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top