There is a private void btnContBalloon_Click(object sender, EventArgs e). Can I make this static because I want to invoke this from static method but I can not.
Making events static is a great way to shoot the foot. A static event has an unlimited life-time. Which makes any event handlers you register for the event live forever too. Which makes any form that contains such an event handler live forever too. A leak.
Registering an event handler for a static event requires code in, say, the FormClosing event handler that explicitly unregisters the handler. You can see this explicitly documented in the MSDN Library article for the SystemEvents class, one of the few examples of a class in the .NET framework that has static events.
The better approach is to keep track of the form instance whose button's Click event should be activated. Something like this:
public partial class Form1 : Form {
public static Form1 MainForm { get; private set; }
public Form1() {
InitializeComponent();
MainForm = this;
}
public void RunClickMethod() {
button1.PerformClick();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
MainForm = null;
base.OnFormClosing(e);
}
}
Which allows client code to do this:
Form1.MainForm.RunClickMethod();
Yes, if that method doesn't need the instance members of the enclosing class you can make it static. Nothing prevents an event handler from being static, if that is the real question.
Bottom line: If that method only uses the sender object (probably the button) and the event args or other static members, then this is perfectly valid and possible.
In general: Yes, eventhandlers can be made static. But the normal rules for static methods apply.
But often the autogenerated code gets into trouble when you change a autogenerated eventhandler to static. I'd do that with manual added eventhandlers, only.
Related
I think the answer is NO but I thought of asking to see if it's possible at all
Scenario: I have a WPF application that uses a class with static events to subscribe interactions between different controls
Basically,
public class EventNotifier
{
public static event EventHandler<SomeEventArgs> EventTriggered;
public static void NotifyEventTriggered(object source, SomeEventArgs eventArgs)
{
if (EventTriggered!= null)
{
EventTriggered(source, eventArgs);
}
}
}
Then from some controls some methods get subscribed:
EventNotifier.EventTriggered+= new EventHandler<SomeEventArgs>(SomeMethodToReceiveEvent);
And from some other controls the events are triggered:
EventNotifier.NotifyEventTriggered(null, eventArgs);
This is all very straightforward. When the controls that subscribed their methods are disposed the events are disposed as well:
EventNotifier.EventTriggered-= new EventHandler<SomeEventArgs>(SomeMethodToReceiveEvent);
Given the nature of WPF that makes memory leaks rife where events are not unsubscribed correctly, until now I've had to manually test every control every time a leak was happening to ensure events were being disposed correctly. This is very time consuming
Some tools that analyze memory usage that I've used are completely incompetent at identifying the event that wasn't unsubscribed that was causing a memory leak
This is why I've been dreaming of creating my own tool to detect every time a method is subscribed to an event and also detect every time it's unsubscribed
I know I could do it in code using properties like:
private static event EventHandler<SomeEventArgs> eventTriggered
public static event EventHandler<SomeEventArgs> EventTriggered
{
add
{
eventTriggered-= value;
eventTriggered+= value;
//Add code here to keep track somewhere of event
}
remove
{
eventTriggered-= value;
//Add code here to keep track somewhere of event
}
}
But my dream tool would be one that is external to my application and hooks up to a process to monitor its events. Am I just dreaming or is this possible in any way?
E.g. for a general type, which subscribe to some events in constructor:
class SomeType
{
public SomeType(...)
{
someEvent1 += ...
someEvent2 += ...
}
}
Where do I unsubscribe from events?
Finalizer?
IDisposable ?
Some method DontForgetToCallMeSoICanUnsubscribeFromEvents()?
Use weak events pattern?
I know it depends. In case of controls (wpf, winforms) there are some events what can be used to subscribe/unsubscribe like Loaded/Unloaded, HandleCreated/HandleDestroyed, etc. But what if parent is a simple object?
And some more specific example: nested ViewModels, where each level is a List<NextLevelVM>, at any level ViewModel can be deleted, does that means what each ViewModel must implement IDisposable (if e.g. it is the right way) where it call Dispose for each item in their list? I tried to use weak events, but that doesn't go well.
I've found a really good way to handle this issue is to create two methods in the page's code behind, that calls methods on your ViewModel to start/stop listening to events depending on whether it's visible or not.
Below I'm using the Appearing functions, but depending on the framework you're using it might be slightly different, but the strategy should work.
In Page class:
protected override void OnAppearing()
{
base.OnAppearing();
_myViewModel.StartListeningToEvents();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_myViewModel.StopListeningToEvents();
}
Then in my ViewModel, I actually subscribe to the events I require:
public void StartListeningToEvents()
{
SomeProperty.PropertyChanged += PropertyUpdated;
}
public void StopListeningToEvents()
{
SomeProperty.PropertyChanged -= PropertyUpdated;
}
void PropertyUpdated(object sender, PropertyChangedEventArgs e)
{
// do stuff
}
My example is for a property change event. But similar code should work for any event.
In this way you're guaranteed that your page is only listening to events when it's open, and you don't need to worry about disposing anything besides calling the one event when the page is no longer open.
I'm pretty new to programming with Class Libraries and I think my question is kind of complicated.
I'm working on my own exception logger. This exception logger has static routines and functions so I don't have to declare it in each of my other classes. (Is this btw a good idea? :/ ) Whenever something goes wrong, a routine is called in the exception logger class. This routine determines what the error message should be based on the number I passed to it.
My goal is as follow:
The exception logger should trigger an event in the GUI. The event in the GUI then shows a custom made message box with the error message in it. I know the possibility of declaring the exception logger in the GUI with WithEvents, but the there is no purpose of having everything static in the exception logger class.
EDIT 1: I'm looking for a way to trigger an event in the GUI project from a ExceptionLogger Class in a Class Library in the same solution without declaring the Class ExceptionLogger in every Class in my GUI project.
EDIT 2: Let me give an example. I have a Class Library named Base. This Class Library contains a Class named ExceptionLogger. This Class in its turn has a Static Routine called Log.
So I have a .dll named Base as a Reference in my main Project called GUI. GUI has a Form MainWindow and 2 Classes named Product and Customer.
What I want is that, for example, the class Customer runs into an Error (by using Try...Catch) and in the Catch part Base.Log(1). The Log routine in ExceptionLogger will look up what the error message has to be and will fire an event in the GUI's MainWindow showing a User Made MessageBox.
The real question is, how do I fire this event from Log into the MainWindow?
EDIT 3: The User Made MessageBox in EDIT 2 is rather a Panel that overlays the MainWindow, not a MessageBox window that opens.
I have found the solution on my own. Any remarks are welcome. Already tnx to the ppl who commented or posted an answer.
This is an example of what I was looking for and it's working.
This is my DLL (namespace Base):
public class ExceptionHandler
{
public static event EventHandler ShowErrorMessage;
public static void test(EventArgs e)
{
ShowErrorMessage("me", e);
}
}
This is the code in my MainWindow:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Base.ExceptionHandler.ShowErrorMessage += ExceptionHandler_ShowErrorMessage;
}
void ExceptionHandler_ShowErrorMessage(object sender, EventArgs e)
{
MessageBox.Show((string)sender);
}
private void Form1_Load(object sender, EventArgs e)
{
Base.ExceptionHandler.test(new EventArgs());
}
}
please help me to find a solution for calling a method automatically when ever a form is loaded. I want to write a piece of code in every form for invoking a license validation for each form. To avoid I placed that code in the program.cs as a static method and now I want to call the method without re writing my form's codes. Please help me on this issue.
Create base class LicensedForm which will provide this functionality:
public class LicensedForm : Form
{
protected override void OnLoad(EventArgs e)
{
// invoking a license validation here
base.OnLoad(e);
}
}
Inherit other forms from this base class instead of Form
public class MainForm : LicensedForm
{
//...
}
You need your forms to handle the Load event. Then run your license-check method in the eventhandlers.
You need to make sure that your method is both public and static, to be able to access it.
private void MainForm_Load(object sender, EventArgs e)
{
Program.CheckLicense();
}
This is somewhat different question or maybe a easy question. but I have this problem now.
I have three forms loginForm, mainForm and subForm.
In my loginForm I have two accounts, one for mainForm access and other for subForm access. The mainFormAccessAccount can access both mainForm and subForm but the subFormAccessAccount can only access subForm. Through mainForm we can create multiple instances of subForm (mainForm is single instance).
Now my problem is: I want to implement different subForm_Closed Event functions for a subForm and its Instances (instances created by mainForm).
I used the below code to create the instances of subForm in subForm.cs
private mainForm MainForm;
internal void RegisterParent(mainForm form)
{
this.MainForm = form;
}
and in mainForm.cs to create instance of subForm, I used the below code:
subForm newSubForm = new subForm();
newSubForm.Show();
newSubForm.RegisterParent(this);
How can I solve this issue?
(I am not sure whether they are called instances or not because I am a Dot net noob)
Thanks in Advance.
If I understand your problem correctly you want two different handlers for close event of the SubForm.
One handler for close events of the SubForm created through subFormAccessAccount
Another handler for close events of the SubForm created through MainForm
As you suspected, this is indeed an easy problem and since you mentioned you are a .net noob I will try to explain in detail.
If I am not wrong you generated the event handler subForm_Closed using Visual studio designer surface. This seems to be the cause of your confusion.
What does the Visual Studio Designer do to generate event handler:
If you open SubForm.cs notice the definition of its constructor. It will be something like this
public SubForm()
{
InitializeComponent();
//May be some other code as well
}
This InitializeComponent method is described in SubForm.designer.cs file () (expand SubForm.cs in solution explorer and you will be able to see it).
One of the lines in InitializeComponent method will be something like this
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SubForm_Closed);
So in effect as soon as you create a SubForm 'instance' (here I mean real object instance and not in the sense you mentioned in your question which is at best a child form) either through subFormAccessAccount or through MainForm, it attached your SubForm_Closed event handler to the FormClosed event.
How can you get the desired behavior?
If you want to handle the closed event in SubForm.cs, you can do something like this
internal void RegisterParent(mainForm form)
{
this.MainForm = form;
this.FormClosed -= SubForm_Closed; //Unhook previous handler
this.FormClosed += SubFormAsChild_Closed; //hook new handler
}
If you want to handle the closed event in MainForm.cs, you can do like this
internal void RegisterParent(mainForm form)
{
this.MainForm = form;
this.FormClosed -= SubForm_Closed;
}
//in MainForm.cs
newSubForm.RegisterParent(this);
newSubForm.FormClosed += newSubForm_Closed;
Several ways to go
Add another constructor to SubForm
e.g.
public SubForm(Boolean argCreatedByMainForm) : this()
{
// save argument in private member variable for use in OnCloseQuery
}
then use
subForm newSubForm = new subForm(true);
newSubForm.Show();
newSubForm.RegisterParent(this);
It's not the way I'd go, because having one form know about another, tends to turn into a maintenance nightmare, but you'd need some more tools in your programming box to implement better solutions. A class to manage the interraction between forms for instance, then abstract them out to interfaces, last but not least inject the behaviour.
Seeing as you are learning, get constructor working, the you can progress to stupidly clever as you pick up the techniques
subForm newSubForm = new subForm();
newSubForm.Show();
newSubForm.RegisterParent(this);
newSubForm.Close += (s, e) =>
{
// Close event will be fired for this instance only.
};
I would recommend to have an other structure of you mainform - subform referencing.
Your Subform is dervived from System.Windows.Forms.Form, which is derived from System.Windows.Forms.Control, which actualy has already one property to store a parent control:
So you should store there the reference to the main form.
The other thing is that you should implement a static method to create subforms in your mainform, which acutaly calls a private methods of the single instance reference to create the real subform - i asume that you you the singleton pattern.
so code would look like this
public class MainForm : System.Windows.Forms.Form
{
// used to hold references to subforms note: not static
private List<SubForm> mySubForms;
// singelton implementation
private static MainForm theInstance = null;
private MainForm()
{
mySubForms = new List<SubForm>();
}
public static MainForm GET_INSTANCE()
{
if (MainForm.theInstance == null)
{
MainForm.theInstance = new MainForm();
}
return MainForm.theInstance;
}
// creates subforms and the references right not:static method as singelton
//pattern is used
public static SubForm CREATE_SUBFORM()
{
SubForm newSub = new SubForm();
newSub.Parent = theInstance;
theInstance.mySubForms.Add(newSub);
return newSub;
}
}
Please aplogize if the code has some typing errors ... i dont have an IDE right now. Obiously I didnt implement the singelton pattern threadsafe...this would be corss the edge for demonstraion purpose.
Edit:
An even better practise would be to let forms comunicate by making use of evetns. This would be the best way if you plan to have a multithreaded application. But you need advanced .Net skills to it this - imo.