Form Designer and Namespaces - c#

I have a static event in a DLL that I use frequently - Toolkit.Dialogs.ExitConfirm
The only way I can use this event is by modifying the line that adds the event in form.Designer.cs. Example:
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.Form1_FormClosing);
becomes
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(Toolkit.Dialogs.ExitConfirm);
If I try to add it via the Properties->Events page, it gives me this error: 'Toolkit.Dialogs.ExitConfirm' is not a valid identifier.
Is there a way to allow Form Designer to reference events from other classes/namespaces?
Edit: some people work better with visual cues, so here's some images to define the issue: http://imgur.com/a/RaLMg
The first image shows how I have to make it work in Visual Studio - an event that calls an event.
The second image shows what I'm actually trying to do.
The third image is the error that occurs when I key in the method name by hand.

I have a static event in a DLL
You don't, you just have a method. FormClosing is the event, your method can be the event handler method if it has the proper signature. The designer simply doesn't support what you try to do, you'll have to stop trying. There are two sane solutions, both involve writing code in the form class. First you can do it in the constructor:
public Form1() {
InitializeComponent();
this.FormClosing += Toolkit.Dialogs.ExitConfirm;
}
Or the sane one since it doesn't make sense for a class to listen to its own events:
protected override void OnFormClosing(FormClosingEventArgs e) {
Toolkit.Dialogs.ExitConfirm(this, e);
if (!e.Cancel) base.OnFormClosing(e);
}
Which has the great advantage of working properly when you derive another form from this one. Which is also a strong hint to what you are probably really should do. It looks like you are trying to write common code for dialogs. The "Toolkit" namespace suggests as much. Make it work well by having this toolkit implement a base form class instead. Now you can design your form class without any code or event handlers:
public partial class Form1 : Toolkit.Dialogs.BaseDialog {
// etc
}
With the assumption that Toolkit.Dialogs.BaseDialog is a class derived from Form that overrides OnFormClosing(). Maybe it should also have a public property named "ConfirmOnClose" of type bool. which enables the "ExitConfirm" logic. You can set that property in the designer without trouble.

The WinForms designer isn't designed to do that. I'm a little surprised it doesn't lose your event the next time you make a change in the designer.
A few ideas on other ways you could make this work:
You could make a Form class that hooks the event for you, and descend all your other forms from that base class. Then you'd get the behavior everywhere.
You could make a utility method that hooks the event for you, and call it from each form's constructor.
You could make an extension method that hooks the event and then shows the form, and call your extension method everywhere you show your forms (instead of calling Show).
The base class is probably the simplest solution, as long as you aren't already using form inheritance for some other purpose.

You can call this Method 'Toolkit.Dialogs.ExitConfirm' On form closing event of your application form and pass required param to Toolkit.Dialogs.ExitConfirm

Related

How to determine that a form has finished opening in C#

I'm having some problems with my form and the business class:
The form does not open until the business class has finished it's work. Every time I call Form1 in Main(), Form1 calls two methods:
InitializeComponents();
testConnection();
testConnection calls the business class and sets the properties of the Form according to the properties of the business class. Like that:
Pingger pingger = new Pingger();
ipLabel.Text = pingger.getLocalIP();
I do not do just these operations, I also do others like the result of a ping. However, Form1 takes a long time to open and when it's open Form1 shows the results. What do I have to do, create Form1, open it, and then after 3 seconds start to process the business class?
What you want is an event raised by your form control. To determine if there is such an event you simply Google the class (ie Form). On the msdn page every property, method and event is listed accompanied with what they do.
What you want is the Shown event. You can add an event to this and then handle whatever it is you want to do. See link below.
http://msdn.microsoft.com/en-us/library/system.windows.forms.form(v=vs.110).aspx
You can subscribe to the Shown event for the form and call your testConnection() method from there.
InitializeComponents();
Shown += (s,e) => testConnection();
You could also use multi-threading to "launch" the testConnection() method. (but then you have the added complexity of making sure the results are in before you rely on them, thread safety, etc...)
I wonder you want to show the form just before the connection is tested?
The idea could be using multi-threading like the Wonderbird suggestion, using some like this:
InitializeComponent();
new Thread(testConnection).Start();

.NET (non-visual) component

I need to create a non-visual component, FooComponent, that will do some management for all controls of type Bar that resides in its form.
I have the following constraints:
The FooComponent can only be added to forms.
Only one FooComponent per form is allowed.
FooComponent should register to the form closing event, and when it fires and to some function on all Bar's and sent the e.Cancel value based on the returned values.
#1 and #2 above should be enforced on run-time as well as design time.
#3 event registration should be made automatically and not by the FooComponent's users.
I searched Google and MSDN for some help and read about Component and ComponentDesigner classes, but I didn't find anything for the rescue.
What should I do?
(1) To control that the component can only be added to a form, use a FooComponent constructor that is passed a form, and don't define the default constructor. It's called like:
FooComponent component = new FooComponent(this);
where the component is created from within the form itself. By not-defining the default constructor, this:
FooComponent component = new FooComponent();
will not compile.
(2) Expose a FooComponent property on the form itself, and in the constructor of the FooComponent, set the passed form's FooComponent to this.
(3) Same thing, in the constructor for the FooComponent, register with the closing event for the form you passed
Put it all together and you get:
public class MyForm : Form {
public FooComponent OwnedComponent { get; set; }
}
public class FooComponent {
public FooComponent (MyForm OwnerForm) {
OwnerForm.OwnedComponent = this;
OwnerForm.FormClosing += MyCallback;
}
private void MyCallback(object sender, FormClosingEventArgs e) {
...
}
}
EDIT
Unfortunately, if you need the default constructor, and if it has to be a true drop-on-the-form Component, there's no way to enforce that a component is only created on a Form, or that the Form only has one instance of the component (not from within the component, anyway).
The problem is twofold:
(1) Dropping a component doesn't add the component to the form, it adds it to the form's components collection. So even if you could get a handle to the parent/owner, it will never be a form.
(2) As Neil pointed out, dropping a component onto a form calls the default constructor, which passes no parameters, and, of course, none of the component's properties (such as site or container) are populated.
Possibly helpful: A component can be designed to be notified when it is created in a couple of ways:
(1) By implementing a constructor that takes an IContainer parameter. When the component is dropped on a form, the generated code will call this constructor, instead. However, it will only do this at runtime, not design time. But the container will be a handle to the form's components collection.
public FooComponent(IContainer container) {...}
(2) By implementing ISupportInitialize. When the component is dropped on a form, the generated code will additionally call BeginInit() and EndInit(). In EndInit(), you can access properties such as the Site and Container. Again, you'll only get this at runtime, not designtime, and throwing an exception here won't stop the component from being created.
Old, but excellent articles on Components and Controls from MSDN Magazine by Michael Weinhardt and Chris Sells.
April 2003 Building Windows Forms Controls and Components with Rich Design-Time Features
May 2003 Building Windows Forms Controls and Components with Rich Design-Time Features, Part 2
These are now .chm help files. You will need to unblock in the file's property page to enable reading the contents after downloading.
I don't think it's possible to define exactly what a contained class can be contained within. I've certainly never seen an instance where I've gotten an error (or even a warning) for setting up a property of one type in another, even in WinForms.
Something you might be able to do is to define a Form-derived ancestor for your forms that contains a reference to your (internally-visible) FooComponent, initializes one on instantiation, and attaches the handlers. For best results it should be parameterless and the only constructor overload, so it forms the base for any constructor your consumers come up with. Then, just make it a house rule that forms derive from your ancestor class and not directly from Form (you might be able to use a code inspection tool like FxCop or similar to enforce this when code is committed to source control). Your users now get a FooComponent in every Form they create, cannot create their own (it's internal and should be in another project with your Form ancestor) and don't have to do anything other than derive from the new class to make their forms behave the way you want.
You are asking for a lot. In general, making components aware of the form they are dropped on is quite difficult. This answer can help you get the event handler implemented. You'll need to implement ISupportInitialize to get the EndInit() call to setup the event handler.
Preventing multiples is quite hard too, I can only think of a custom designer that can step in early enough to prevent the 2nd one from being added.

Where to register for C# events?

I am currently transitioning from VB to C# and am having some issues with regards to registering my interest in an event.
When using VB it was simply a case of specifying that a method Handles and event, often this was generated by using the object events list. While I can easily use the Class.event += delegate in C# I am unsure where the best place is to place the code to do this.
Am I best placing it inside of the InitializeComponent() as per the generated code (say if you select the event in the from designer) or should I place it inside the constructor for better readability/maintenance. If inside the constructor, should it be before or after the call to InitializeComponent()?
When you are doing WinForm development (judging from InitializeComponent() function mentioned), usually you assign the handler using Visual Studio. You look up the properties of your control, click on the lightning icon to get the list of all events, find your event, and either double click on it (to create a new handler), or select existing handler from the list. Visual Studio will add the wiring of this in the generated code, so you don't have to worry about it.
I always create a private method called Init() and place it there, and then call that method from the constructor or the Form_Load event handler. It's semantically better, IMO, than doing it within the constructor proper. And you don't want to place it within InitializeComponent(), because next time you change something in your designer it's likely to delete any manually-added code there.
Sometimes Visual Studio's designer can mess up the code, so adding the event handlers within InitializeComponent can create a headache, it would be better to do it something like this
public Form1(){
InitializeComponent();
WireUpEvents();
}
public void WireUpEvents(){
this.fooEvent += new EventHandler(foo_handler);
.... etc ....
}
And make sure that you remove the event handlers in the Form's Dispose function also...
public void UnWireEvents(){
this.fooEvent -= new EventHandler(foo_handler);
.... etc ....
}
As you design the form, Visual Studio will change the code within the InitializeComponent() method located in form.design.cs, so it is imperative that you do not manually edit this code..
It depends, but most of the time, yes.
Use InitializeComponent when you want the event to be hooked for the entire duration of the Form (I'm assuming you're talking about Forms/UserControls/etc.). In other cases, you'll want finer grained control of when the Event is handled.
Keep in mind that you'll want to unhook all of these events (using the -= syntax) when you're Disposing the Form, or no longer want to handle the event. Keeping the event handler delegates attached is one of the most common managed memory leaks around.
Do not manually add code to the InitializeComponent() method. This method is code generated, so as soon as you change your form, any logic that you've added manually to this method will be wiped out.
I usually add a method to handle the Form's Load event and put my event registrations there.
If you have the InitializeComponent() method you're using the designer so you can bind events directly in the designer if you like. To do this, click the lightning bolt icon in the properties window and you'll see a list of all the events for the selected object. You can just type the name of the event in there and it'll create the code for you.
If you're not a fan of the designer, bind them after your InitializeComponent call and make sure you detach them when you're done (in Dispose()).
2 ways of doing this. You can either create you own method which you call in your Constructor which in turn creates the Event Handler, or you can just place them in your Constructor. Probably a good idea to remove the Event Handlers in your Finalizer/Destructor code.
I would place it after InitializeComponent, since you might be registering events against a child control/object, like a button, and you will want to be sure the object has been created already.
There will be cases where you wire up to events dynamically/conditionally in other places, such as in response to some other event.

Winform & user control - C#

I have a Form and a UserControl. The UserControl has a menu, and the form has a tabstrip (General, Food, Vitamins etc).
In the UserControl, I have the following code: (Form name is frmForm, the tab names in the form are tabGeneral,tabFood, tabVitamins)
frmForm fm=new frmForm();
fm.tabMain.Selected=tabVitamins;
I call these line from the UserControl to capture the tab to get selected on the form, but it does not select the vitamins tab.
Where am I going wrong? I have access specifier as Protected Internal for tabs in the form.
Please advice.
Thanks,
Karthick
When you write new frmForm(), you're creating a completely new instance of frmForm, which is then discarded.
To get the frmForm instance that holds your control, call the FindForm() method and cast to frmForm.
For example:
frmForm myForm = FindForm() as frmForm;
if(myForm != null)
myForm.tabMain.SelectedTab = myForm.tabVitamins;
If the control is on some other form, this code won't do anything.
By the way, Hungarian notation is frowned upon in .Net.
Your form should probably be named something like MainForm.
SLaks has correctly pointed out your fundamental error, and given you a valid example of a way, via a call to the method 'FindForm, to get the Form the UserControl is sited on.
It may be valuable to you to keep in mind that a UserControl (and all Controls) also has a 'Parent property, but, of course, a UserControl could be placed inside another Control on a Form (like your UserControl could be inside a Panel on the Form) : in that case the UserControl's Parent would be the control it's inside on the Form (like, a Panel), not the Form itself, but 'FindForm will do the right thing to get you the Form it's on.
However you are calling a Method every time you use 'FindForm, and "best practice" suggests that what you want to do is to "inject" a reference to the Form into the UserControl at run-time so that it can always access its Form property easily, without calling a 'Method.
In your example, on a practical level, this (calling the Method) may make almost no difference in performance, but, imho, as you get to a place with WinForms and .NET where you might have a UserControl that will need access to its Parent Form very frequently, this will pay off, and it's a better way to structure your code in the long run, for maintenance.
Wes showed you one way you can "embed" (inject) the UserControl's hosting Form : using an overloaded constructor for the UserControl. But that requires you to modify the Designer.cs file in standard WinForms, and I strongly advise you against that, even though it will work. Particularly if you are just "getting your feet on the ground" in .NET, I strongly advise you against modifying it, or anything having to do with the Form's constructor and its internal call to : InitializeComponent();
Also, as you progress with WinForms you are going to meet many situations where you are going to want instances of "objects" (a Control, a Form, an instance of a Class) to contain references to other instances of "objects.
If you can understand and use one simple use of "injection" here, you are going to make progress to make yourself ready to handle more complex .Net programming in the future.
Another way is to put a Public Property in the UserControl that can be set in code from the MainForm. In the UserControl something like :
private frmForm ParentForm;
public frmForm UCParentForm
{
set { ParentForm = value; }
}
So then in your main form's code, perhaps in the Load event like this :
private void frmForm_Load(object sender, EventArgs e)
{
TheUserControl.UCParentForm = this;
}
or when you need to, you set the UserControl's 'ParentForm property once. So you have eliminated using the method 'FindForm().
In this case, if you only want access to a specific control on the UserControl's Parent Form, like a TabControl, you might consider that you want to make the Property you set of type TabControl, rather than Form : the same coding technique shown above can be used in the UserControl :
private TabControl mainFormTabControl;
public TabControl MainFormTabControl
{
set { mainFormTabControl = value; }
}
imho, it is when you are creating UserControls dynamically at run-time, using an overloaded constructor, as Wes suggests, is the best strategy. And using overloaded constructors has many, many others uses in .NET that you'll get into.
good luck !
You should not be creating a new frmForm() inside the user control. You could pass a reference to the frmForm to the user control.
In your user control constructor try something like this.
private frmForm fm;
public YourUserControl(frmForm fm)
{
this.fm = fm;
}
Then you could use.
fm.tabMain.Selected=tabVitamins;
Does that help?

Inheriting Event Handlers in C#

I've kind of backed myself into a corner here.
I have a series of UserControls that inherit from a parent, which contains a couple of methods and events to simplify things so I don't have to write lines and lines of near-identical code. As you do. The parent contains no other controls.
What I want to do is just have one event handler, in the parent UserControl, which goes and does stuff that only the parent control can do (that is, conditionally calling an event, as the event's defined in the parent). I'd then hook up this event handler to all my input boxes in my child controls, and the child controls would sort out the task of parsing the input and telling the parent control whether to throw that event. Nice and clean, no repetitive, copy-paste code (which for me always results in a bug).
Here's my question. Visual Studio thinks I'm being too clever by half, and warns me that "the method 'CheckReadiness' [the event handler in the parent] cannot be the method for an event because a class this class derives from already defines the method." Yes, Visual Studio, that's the point. I want to have an event handler that only handles events thrown by child classes, and its only job is to enable me to hook up the children without having to write a single line of code. I don't need those extra handlers - all the functionality I need is naturally called as the children process the user input.
I'm not sure why Visual Studio has started complaining about this now (as it let me do it before), and I'm not sure how to make it go away. Preferably, I'd like to do it without having to define a method that just calls CheckReadiness. What's causing this warning, what's causing it to come up now when it didn't an hour ago, and how can I make it go away without resorting to making little handlers in all the child classes?
Declare the parent method virtual, override it in the child classes and call
base.checkReadyness(sender, e);
(or derevation thereof) from within the child class. This allows for future design evolution say if you want to do some specific error checking code before calling the parent event handler. You might not need to write millions of event handlers like this for each control, you could just write one, hook all the controls to this event handler which in turn calls the parent's event handler.
One thing that I have noted is that if all this code is being placed within a dll, then you might experience a performance hit trying to call an event handler from within a dll.
I've just come across this one as well, I agree that it feels like you're doing everything correctly. Declaring the method virtual is a work-around at best, not a solution.
What is being done is valid - a control which only exists in the derived class, and the derived class is attaching an event handler to one of that control's events. The fact that the method which is handling the event is defined in the base class is neither here nor there, it is available at the point of binding to the event. The event isn't being attached to twice or anything silly like that, it's simply a matter of where the method which handles the event is defined.
Most definitely it is not a virtual method - I don't want the method to be overridable by a derived class. Very frustrating, and in my opinion, a bug in dev-studio.
I too have experienced this issue because in earlier versions of VS, you could "inherit" the event handlers. So the solution I found without having to override methods is simply to assign the event handler somewhere in the initialization phase of the form. In my case, done in the constructor (I'm sure OnLoad() would work as well):
public MyForm()
{
InitializeComponent();
btnOK.Click += Ok_Click;
}
...where the Ok_Click handler resides in the base form. Food for thought.
I've just run into the exact problem Merus first raised and, like others who posted responses, I'm not at all clear why VS (I'm now using Visual C# 2010 Express) objects to having the event handler defined in the base class. The reason I'm posting a response is that in the process of getting around the problem by making the base class code a protected method that the derived classes simply invoke in their (essentially empty) event handlers, I did a refactor rename of the base class method and noticed that the VS designer stopped complaining. That is, it renamed the event handler registration (so it no longer followed the VS designer's convention of naming event handlers with ControlName_EventName), and that seemed to satisfy it. When I then tried to register the (now renamed) base event handler against derived class controls by entering the name in the appropriate VS event, the designer created a new event handler in the derived class which I then deleted, leaving the derived class control registered to the base class (event handler) method. Net, as you would expect, C# finds what we want to do legit. It's only the VS designer that doesn't like it when you following the designer's event handler naming convention. I don't see the need for the designer to work that way. Anywho, time to carry on.
If your event is already defined in your parent class, you do not need to rewire it again in your child class. That will cause the event to fire twice.
Do verify if this is what is happening. HTH :)
This article on MSDN should be a good starting points: Overriding Event Handlers with Visual Basic .NET. Take a look at the How the Handles Clause Can Cause Problems in the Derived Class section.
Why not declare the method as virtual in the parent class and then you can override it in the derived classes to add extra functionality?
Forget that it's an event handler and just do proper regular method override in child class.
Here's what I did to get base methods called in several similar looking forms, each one of them having a few extra features to the common ones:
protected override void OnLoad(EventArgs e)
{
try
{
this.SuspendLayout();
base.OnLoad(e);
foreach (Control ctrl in Controls)
{
Button btn = ctrl as Button;
if (btn == null) continue;
if (string.Equals(btn.Name, "btnAdd", StringComparison.Ordinal))
btn.Click += new EventHandler(btnAdd_Click);
else if (string.Equals(btn.Name, "btnEdit", StringComparison.Ordinal))
btn.Click += new EventHandler(btnEdit_Click);
else if (string.Equals(btn.Name, "btnDelete", StringComparison.Ordinal))
btn.Click += new EventHandler(btnDelete_Click);
else if (string.Equals(btn.Name, "btnPrint", StringComparison.Ordinal))
btn.Click += new EventHandler(btnPrint_Click);
else if (string.Equals(btn.Name, "btnExport", StringComparison.Ordinal))
btn.Click += new EventHandler(btnExport_Click);
}
The chance of an omission of using the right fixed button name looks the same to me as the chance of not wiring the inherited handler manually.
Note that you may need to test for this.DesignMode so that you skip the code in VS Designer at all, but it works fine for me even without the check.

Categories

Resources