Using this code, i am adding an eventhandler to the RootFrame.Obscured.
(Application.Current as App).RootFrame.Obscured += onObScured;
Since the RootFrame can be accessed from every class in the App, what happens if i add different eventhandlers from different classes?
Example:
class A{
(Application.Current as App).RootFrame.Obscured += onObScuredA;
private void onObScuredA(object sender, ObscuredEventArgs e) {
//Some code here
}
}
class B{
(Application.Current as App).RootFrame.Obscured += onObScuredB;
private void onObScuredB(object sender, ObscuredEventArgs e) {
//Some other code here
}
}
When the event is triggered, will both onObScuredA() and onObScuredB() be triggered if there has been created an instance of both A and B?
Is the correct way, to add the eventhandlers, and their respective methods on the App.xaml.cs class so i can be certain which eventhandlers are added?
Thanks.
You can add as many event handlers onto an event as you want, they will all be invoked. That is the nature of events, when they fire, all event handlers handle this event.
So, the answer is "they both will be triggered". Now, this may or may not be what you want, but adding new event handler does not replace previous event handlers.
Read more on MSDN: Handling and Raising Events.
Related
I would like to raise an event and notify existing subscribers if any exist. But I also expect new subscribers to be notified of all events raised so far as soon as they subscribe. Is this possible out of the box or do I need to implement that functionality myself? Right now my code look like this:
public delegate void GridCompiled(int gridsize);
public event GridCompiled OnGridCompiled;
ctor(){
if (OnGridCompiled != null)
OnGridCompiled(gridsize);
}
If event has 0 subscribers it won't be raised and it also won't be raised for subscribers that subscribe after event has been raised.
In case I need to implement that myself, what are my options?
There is no tracking of raising events, so you would have to implement the functionality yourself. You would need a list to store your previous event arguments in order and execute the related events when a new event listener is added:
class Example {
private readonly List<GridCompiledEventArgs> m_previousEventArgs = new List<EventArgs>();
private EventHandler<GridCompiledEventArgs> m_gridCompiled;
public event EventHandler<GridCompiledEventArgs> GridCompiled {
add {
//Raise previous events for the caller
foreach(GridCompiledEventArgs e in m_previousEventArgs) {
value(this, e);
}
//Add the event handler
m_gridCompiled += value;
}
remove {
m_gridCompiled -= value;
}
}
protected virtual void OnGridCompiled(GridCompiledEventArgs e) {
if (m_gridCompiled != null) {
m_gridCompiled(this, e);
}
m_previousEventArgs.Add(e);
}
}
There are two things you have consider for this solution. If you want to adress them, your solution will become more complex:
If GridCompiledEventArgs can be changed by an event handler (e.g. to return a status to the caller), the event args will be stored in the previous event list with those changes. Also, if an event handler keeps a reference to the event args they might even change it later. If you don't want that, you have to store a copy in m_previousEventArgs and create another copy before you raise the "historic" event.
It is best practice to allow derived classes to override the OnGridCompiled method instead of handling the event or changing its behavior. If a derived class changes OnGridCompiled to intercept the event and not raise it in certain cases, this behavior will not always apply for the "historic" event, since it is raised without OnGridCompiled (which might be just the behavior you want). If you want to change that you have to implement a solution that goes through OnGridCompiled. If this is an option for you, you can avoid this problem by making the class sealed and the OnGridCompiled method private instead of protected virtual.
I am working on a UserControl for selecting special files, in this control there is a TreeView which gets populated with nodes when user selects some file. Also user can remove the files from this treeview!
I am using this control in a wizard form. In this wizard form there is a button named buttonNext and this button is disabled by default.
How can I create an event for the treeview in the usercontrol that when it gets populated it notify the next button in wizard form to get enabled and if user removes all files from that treeview it notify the button to get disabled again.
P.S: Selecting files (browser dialog and stuff like that) are all done within this usercontrol, so in my wizard form I have no access to the things that is going on in this component, but only I set the TreeView itself as public so I can read its nodes in my wizard form.
I know how to subscribe to events but never created any event myself :(
Declare events on your CustomControl:
public event EventHandler DataPopulated;
public event EventHandler DataRemoved;
Common practice is creating protected virtual methods (for possible overriding them in descendant classes), named On<EventName> which will verify that event has attached handlers and raise event, passing required arguments:
protected virtual void OnDataPopulated()
{
if (DataPopulated != null)
DataPopulated(this, EventArgs.Empty);
}
NOTE: If you need to pass some data to event handlers, then use generic EventHandler<DataPopulatedEventArgs> delegate as event type, where DataPopulatedEventArgs is a class, inherited from EventArgs.
Then just call this method just after your data was populated:
treeView.Nodes = GetNodes();
OnDataPopulated();
Then just subscribe to this event and enable your next button:
private void CustomControl_DataPopulated(object sender, EventArgs e)
{
buttonNext.Enabled = true;
}
Who is the one populating the TreeView? The one loading the data on it could enable the Next button when it has finished the loading. Am I missing something?
By the way, you create an event like this:
public event EventHandler<EventArgs> YouEventName;
And you call it like a method:
this.YourEventName(this,EventArgs.Emtpy);
Best practices say that you should create a method to call it like this:
protected virtual void OnYourEventName()
{
if (this.YourEventName != null)
{
this.YourEventName(this, EventArgs.Empty);
}
}
Check out this MSDN article for a complete tutorial on how to create and fire events.
http://msdn.microsoft.com/en-us/library/aa645739(v=vs.71).aspx
You can just propogate the event of the Treeview.
You can add this to your custom control, and it will have a SelectedNodeChanged event.
public event EventHandler SelectedNodeChanged
{
add { tree.SelectedNodeChanged += value; }
remove { tree.SelectedNodeChanged-= value; }
}
Creating a new event
public event EventHandler<EventArgs> myEvent;
You then invoke it from some method
this.myEvent(sender, e);
The actual event would look something like this:
protected void MyEvent(object sender, EventArgs e)
{
//Your code here
}
Your code can be like this:
public delegate void ChangedEventHandler(object sender, EventArgs e);
class TreeViewEx : TreeView
{
...
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
}
and it usage
TreeViewEx tree = ...
tree.Changed += new EventHandler(TreeChanged);
// This will be called whenever the tree changes:
private void TreeChanged(object sender, EventArgs e)
{
Console.WriteLine("This is called when the event fires.");
}
I have a UserControl, and I need to notify the parent page that a button in the UserControl was clicked. How do I raise an event in the UserControl and catch it on the Main page? I tried using static, and many suggested me to go for events.
Check out Event Bubbling -- http://msdn.microsoft.com/en-us/library/aa719644%28vs.71%29.aspx
Example:
User Control
public event EventHandler StatusUpdated;
private void FunctionThatRaisesEvent()
{
//Null check makes sure the main page is attached to the event
if (this.StatusUpdated != null)
this.StatusUpdated(this, new EventArgs());
}
Main Page/Form
public void MyApp()
{
//USERCONTROL = your control with the StatusUpdated event
this.USERCONTROL.StatusUpdated += new EventHandler(MyEventHandlerFunction_StatusUpdated);
}
public void MyEventHandlerFunction_StatusUpdated(object sender, EventArgs e)
{
//your code here
}
Just add an event in your control:
public event EventHandler SomethingHappened;
and raise it when you want to notify the parent:
if(SomethingHappened != null) SomethingHappened(this, new EventArgs);
If you need custom EventArgs try EventHandler<T> instead with T beeing a type derived from EventArgs.
Or if you are looking for a more decoupled solution you can use a messenger publisher / subscriber model such as MVVM Light Messenger here
I have a UserControl which contains 3 labels. I want to add an event for it, which occurs when the text of one of the labels changed.
I am using Visual Studio 2010
First, you need to declare the event within your class (alongside your methods and constructors):
public event EventHandler LabelsTextChanged;
Then you need to create a method to handle the individual labels' TextChanged events.
private void HandleLabelTextChanged(object sender, EventArgs e)
{
// we'll explain this in a minute
this.OnLabelsTextChanged(EventArgs.Empty);
}
Somewhere, probably in your control's constructor, you need to subscribe to the label's TextChanged events.
myLabel1.TextChanged += this.HandleLabelTextChanged;
myLabel2.TextChanged += this.HandleLabelTextChanged;
myLabel3.TextChanged += this.HandleLabelTextChanged;
Now for the HandleLabelsTextChanged method. We could raise LabelsTextChanged directly; however, the .NET framework design guidelines say that is it a best practice to create an OnEventName protected virtual method to raise the event for us. That way, inheriting classes can "handle" the event by overriding the OnEventName method, which turns out to have a little better performance than subscribing to the event. Even if you think you will never override the OnEventName method, it is a good idea to get in the habit of doing it anyway, as it simplifies the event raising process.
Here's our OnLabelsTextChanged:
protected virtual void OnLabelsTextChanged(EventArgs e)
{
EventHandler handler = this.LabelsTextChanged;
if (handler != null)
{
handler(this, e);
}
}
We have to check for null because an event without subscribers is null. If we attempted to raise a null event, we would get a NullReferenceException. Note that we copy the event's EventHandler to a local variable before checking it for null and raising the event. If we had instead done it like this:
if (this.LabelsTextChanged != null)
{
this.LabelsTextChanged(this, e);
}
We would have a race condition between the nullity check and the event raising. If it just so happened that the subscribers to the event unsubscribed themselves just before we raised the event but after we checked for null, an exception would be thrown. You won't normally encounter this issue, but it is best to get in the habit of writing it the safe way.
Edit: Here is how the public event EventHandler LabelsTextChanged; line should be placed:
namespace YourNamespace
{
class MyUserControl : UserControl
{
// it needs to be here:
public event EventHandler LabelsTextChanged;
...
}
}
Here are the framework design guidelines on event design for further reading.
First you should declare an event in your usercontrol for example:
public event EventHandler TextOfLabelChanged;
then you have to call the call back function that is bound to your event(if there's any) in runtime.You can do this by handling the TextChanged event of a label like this:
public void LabelTextChanged(object sender,EventArgs e)
{
if(TextOfLabelChanged!=null)
TextOfLabelChanged(sender,e);
}
You can have your own EventArgs object if you like.
somewhere in your code you should bound your label TextChanged event to this method like this:
_myLabel.TextChanged+=LabelTextChanged;
public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;
// ...
protected void MyTextBox_TextChanged(object sender, EventArgs e)
{
if (LabelTextChanged != null) {
LabelTextChanged(this, e);
}
}
compile error, which says: "Expected class, delegate, enum, interface, or struct" on the second line it seems to have a problem with "event...
These 2 lines need to be INSIDE the class declaration.
public delegate void TextChangedEventHandler(object sender, EventArgs e);
public event TextChangedEventHandler LabelTextChanged;
There is a very simple way to do that!
On the UserControl Form :
change properties to public to access everywhere
on the main form , where you are using UserControl:
.5: in the using region add using userControl1=UserControl.userControl1
1.Add 'Laod' event to your UserControl :
this.userControl1.Load += new System.EventHandler(this.userControl1_Load);
2.In the userControl1_Load :
private void userControl1_Load(object sender, EventArgs e)
{
(sender as UserControl1).label1.TextChanged += label1_TextChanged;
//add a 'TextChanged' event to the label1 of UserControl1
OR use direct cast:
((UserControl1) sender).label1.TextChanged += label1_TextChanged;
}
3.In th label1_TextChanged:
private void label1_TextChanged(object sender, EventArgs e)
{
//do whatever you want
}
You must be declaring the event and delegate within the Namespace. Try to bring the code within the class Scope. It will run fine.
This is a C# question. I have a user control A. A contains another user control B. B has an event called BEvent. I want to expose this event in A so anyone who uses control A can subscribe BEvent. How can I write code to implement this design? Thanks.
Inside your user control A you could expose the event of control B like this...
public event EventHandler EventA
{
add { _control.EventB += value; }
remove { _control.EventB -= value; }
}
You should look at the delegate which event B is using, and ensure that event A matches. In this example i just selected EventHandler because that is quite common when developing User Controls
public delegate void EventHandler(object sender, EventArgs e);