I recently created a Silverlight 3 app in which I created some UI elements in the code behind and added them at run-time dynamically.
I was hoping to just use the built-in MouseButtonEventArgs or the sender object to get a reference to the instance that was clicked, however I noticed once I started that this was not the case. I was not able to access any properties of the object that triggered the event and program against it.
void myFunc(object sender, MouseButtonEventArgs e)
{
//Can't do this :(
sender.someProperty = someValueToUpdate;
//or this
MyClass foo = sender as MyClass;
foo.someProperty = someValueToUpdate;
}
I ended up just writing a CustomEventArgs object to pass an instance, but it surprised me that this wasn’t a default behavior.
Can anyone shed some light as to WHY the sender object doesn’t contain a reference to the object that triggered the event?
Also, here is what I did to get that instance.
myObject.myEvent += new CustomEvent(myFunc);
...
void myFunc(object sender, CustomEventArgs e)
{
e.MyProperty = someValueToUpdate;
}
...
public class MyClass
{
public MyProperty = 0;
public event CustomEvent myEvent;
protected virtual void MyEventMethod(CustomEventArgs e)
{
if (myEvent != null){myEvent(this, e);}
}
public MyClass ()
{
this.MouseLeftButtonDown += new MouseButtonEventHandler(this_MouseLeftButtonDown);
}
void rect_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
CustomEventArgs e2 = new CustomEventArgs(this);
MyEventMethod(e2);
}
}
public class CustomEventArgs : EventArgs
{
private readonly MyClass myProperty;
public CustomEventArgs(MyClass myProperty) { this.myProperty = myProperty; }
public MyClass MyProperty { get { return myProperty; } }
}
public delegate void CustomEvent(object sender, CustomEventArgs e);
The
MouseEventArgshas aOriginalSourceproperty. Its this property which holds a reference to the object that originally triggered it.The
senderargument quite rightly is set to the instance of the object against which you attached the event handler. Perhaps a simple experiment will make how this hangs together clearer. In Visual Studio create a Silverlight Application. Make the content of the MainPage.xaml look like this:-And in MainPage.xaml.cs add this code:-
Note how this same handler is attached to three different items in the XAML but not to the TextBlocks themselves. Clicking the “First Top Item” gets you this:-
Sender: TopPanel, Text block: First Top ItemSender: OuterPanel, Text block: First Top ItemSender: LayoutRoute, Text block: First Top ItemThe handler fires 3 times once for each item it is attached to as can be seen by the sender being different for each one. However the OrignalSource it the TextBlock that was actually clicked on despite it not having any handler attached. Also note that the OriginalSource remains the same as it bubbles up the ancestor elements.
Click on the area below the Stack panels. You only get:-
Sender: LayoutRoot, Text block: Not from a text blockOf interest also is that clicking in the Listbox results in no items being added at all, you might expect to the same ase the above line. Clearly ListBox handles the mouse down and therefore sets the event args
Handledproperty toTruepreventing further bubbling.