Initializing Form Controls - c#

I have a dialog box in my program where a user can change certain settings. When the form is closed, the changes are stored in the app's settings file.
Every time the dialog loads, the settings are restored in the constructor of the form. This creates a problem: the CheckedChanged event (in the case of a checkbox as an example) will always be triggered by the time the form fully opens, without the user doing anything!
I have not tried this, but it is my guess one way to overcome this problem would be to pull the initial statuses of the controls in the designer under Data->Application Settings. But this approach requires a separate setting for every control - not practical due to the large number of controls being one problem.
Is there a (better) way to pre-initialize controls on a form without triggering the CheckedChange event?

You could create a class-level variable called IsFormLoading. Set it to True at the beginning of your constructor, then set it to False at the end, after all the controls have been initialized and settings have been restored.
Each of the events on the form that you don't want to be triggered could check if (IsFormLoading) and just return;.

I'm assuming you have event subscriptions in InitializeComponent() method, something the following line :
private void InitializeComponent() {
...
this.checkBox1.CheckedChanged += new System.EventHandler(this.checkBox1_CheckedChanged);
...
}
and that you restored the form's settings after the InitializeComponent() method is called in your constructor.
If so, why not try to defer the event subscriptions after all the controls are fully initialized with your saved settings. Remove all event subscription (Event += Handler) from InitializeComponent() and place it after the settings are restored.
class Form1 : Form {
public Form1() {
InitializeComponent(); // remove event subscriptions from InitializeComponent
ApplySettings(); // restore settings
AttachEventHandlers(); // subscribe to events here
}
}

So the basic over-view is the pop-up shows, user checks some boxes, closes the form, and changes are saved right?
First question: If your just saving the current state of the controls (checked, not-checked,etc), why even deal with the CheckedChange event? Why not just save all the values of the controls in the Form.FormClosing event? I mean I understand the changed event is called because you are setting the values controls in the form load event, but why bother with the changed event unless you are doing something when the change event is fired??
If you really want to use the CheckedChange event though to perform some actions then you could use a counter like so (top of my head code so may be a little buggy):
private int _loadCount;
private void Form1_Load(object sender, System.EventArgs e)
{
_loadCount = 0;
//Code to load values for controls...
}
private void CheckBox1_CheckedChanged(Object sender, EventArgs e)
{
_loadCount++;
if(_loadCount > 1)
{
//Do something here...
}
else
{
//Do nothing, return false, etc...
}
}
In any case, AFAIK the controls changed event always fires regardless of how the controls value was changed (user click, via code, etc).

Related

Is there an event that fires after load for a user control?

I'm using User Controls in C# winforms, and I would like some code to be executed after the load event, and after the control has been shown. If no such event exists, is it possible to make one?
You could use one of events from this list. OnPaint would be most likely candidate.
Form Events:
Construtor
Load
Layout
Activated
Paint­
Closing
Closed
Deactivate
Dispose
and for Controls:
Enter
GotFocus
Leave
Validating
Validated
LostFocus
If you can't find one that fits you needs, this article explains how to construct and fire event.
Create a public method in user control
Call the method on Parent win-form Shown Event
This will call the code you want to run once.
You can also use user-control paint event, but this will Expensive call. Because your code will execute every time the control is redrawn.
So it is better to use a flag which you can determine whether to run the code or not
i.e.
private bool _run =true;
private void Control_Paint(object sender, PaintEventArgs e)
{
if(!_run) return;
//call the code you need to run
_run = false;
}

how to access a user define controls iner controls in parent form

I'm new to windows forms programming so my question may sound little strange.
I have created a user define control (countdown timer) now I'm creating n no of it dynamically in a form by Click of a button (Add new timer) its working well and good.
Here is the Creation Code
private void Addnew_Click(object sender, EventArgs e)
{
UserControl1.userControl11 = new UserControl1();
flowLayoutPanel1.Controls.Add(userControl11);
}
My user control has a Reset button that reset all the content inside the user define control.
it is also working, but What I want Allow user to reset all the Created timers using the “Reset All” button on the form.
Okay one way to do this.
Create a List<UserControl1> private member on your form called say _myUserControls
In your Addnew Handler add it to the list.
If you have a remove button, don't forget to remove from _myUserControls as well.
Add a Reset method to your UserControl1, that does what it needs to do.
Then in your Reset all button click handler
foreach(UserControl1 ctrl in _myUserControls)
{
ctrl.Reset();
}
Jobs a good 'un
The answer I referred you to in comments, would be a way of finding all instances of your UserControl1 class, so you wouldn't need an internal list.

Creating Event for Multiple Forms

I have tried a bunch of different things, so obviously I am now stuck... I have created a form, it has a button on it - that when clicked creates a new form. I can click away and create multiple forms this way. What I would like and can not get to work is to have the main form have a second button on it - that when clicked will change all of the background colors on the secondary forms.
Thanks - I am guessing I close, but then again - close doesn't work...
Bascally you do not need event or delegate type of things to solve this issue. In your secondary forms write a public method to change background color. Keep a list of secondary forms and when button is clicked just loop through all your secondary forms and call the color changing methods
Using events
In your parent form do something like this.
private event Action<Color> ChangeColor;
private void CreateAndShowForm()
{
var form2 = new Form2();
ChangeColor += form2.changeColor;
/*do other stuff to show form*/
}
private void button1_Click(object sender, EventArgs e)
{
ChangeColor(Color.Red);
}
In the child forms
public void changeColor(Color obj)
{
/*change background color*/
}
There are a few ways to achieve this, but one way is to keep a collection of all child Forms in the main form and call a custom change background color method on each of them. You can create a ChildFormBase class that they all can inherit from where you can define the method to avoid repeating it in all child forms.
You can also do this with an event that you raise in the MainForm that the child forms can subscribe to.
In .NET, when an event is raised, all the objects listening to it (registered as event listeners) are notified that the event has been raised and execute the respective event handler. Therefore, in your case, each subform should be registered to the specific event of the main form, as an event listener. Each time the main form raises the event, the subforms will be notified that the event has been raised and act accordingly.
You could see this as a guide to the events paradigm in C#.
Hope I helped!

Databound control won't lose focus [duplicate]

I have a Windows Forms Application. I have several forms in this application (a main form, and several specialized forms), and on only one form, click events are not firing for any of my buttons.
It is not that the code in the handler is broken. This can be determined by the fact that a breakpoint on the first line of the handler is never reached when clicking the button.
Other events are working (I'm using CheckedChanged events on this form and they are behaving).
My team members have reviewed, and also can't spot the problem.
Here is a simplified view of my code:
Designer Generated Code
partial class MyForm
{
private System.Windows.Forms.Button addButton;
private void InitalizeComponent()
{
this.addButton = new System.Windows.Forms.Button();
this.addButton.Name = "addButton";
// Drawing statements here
this.addButton.Click += new System.EventHandler(this.addButton_Click);
this.Controls.Add(this.addButton);
}
}
My Code
public partial class MyForm : Form
{
public MyForm()
{
InitializeComponent();
}
private void addButton_Click(object sender, EventArgs e)
{
MessageBox.Show("The debugger is not reaching a break point on this line");
}
}
Edit: Additional Information from Testing
There are several data-bound dropdownlists in my form. I have discovered that the click event only fails to fire if I make a selection in a drop down box first.
If I make no selections, the break point in the button's handler fires. Otherwise it doesn't. There are no events registered on these drop down lists.
Here is the reason:
When using data binding, when you enter a value in a data bound control, it first tries to validate entry and then if the entry was valid, data binding will put the value in data source, but if a validation error occurs validation returns false and your control goes to invalid mode.
When a child control of form didn't validate, by default you can not change focus from invalid control.
Click on a button by default causes validation of the control that are losing the focus, so you can't click on button, as you see your button reflect to mouse but not actually click.
The same problem will happen if you handle Validating event of a control like TextBox and set e.cancel = true.
Here is the fix:
you can fix this behavior using either of following options:
Set CausesValidation property of your button to false
Set AutoValidate property of your form to AutoValidate.EnableAllowFocusChange
This will do the trick for you
Change
public ScheduleMeeting()
{
InitializeComponent();
}
to
public MyForm()
{
InitializeComponent();
}
I have discovered the issue after further testing.
I the issue is not with button events, but with the form becoming blocked after making a selection from a drop down box.
I have not yet discovered why the form blocks after the drop down is selected (it has no events, but does have databinding, so there are some possible causes there).
Thank you for all your help!

Is there any way to detect a mouseclick outside a user control?

I'm creating a custom dropdown box, and I want to register when the mouse is clicked outside the dropdown box, in order to hide it. Is it possible to detect a click outside a control? or should I make some mechanism on the containing form and check for mouseclick when any dropdownbox is open?
So I finally understand that you only want it to close when the user clicks outside of it. In that case, the Leave event should work just fine... For some reason, I got the impression you wanted it to close whenever they moved the mouse outside of your custom dropdown. The Leave event is raised whenever your control loses the focus, and if the user clicks on something else, it will certainly lose focus as the thing they clicked on gains the focus.
The documentation also says that this event cascades up and down the control chain as necessary:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached. For example, assume you have a Form with two GroupBox controls, and each GroupBox control has one TextBox control. When the caret is moved from one TextBox to the other, the Leave event is raised for the TextBox and GroupBox, and the Enter event is raised for the other GroupBox and TextBox.
Overriding your UserControl's OnLeave method is the best way to handle this:
protected override void OnLeave(EventArgs e)
{
// Call the base class
base.OnLeave(e);
// When this control loses the focus, close it
this.Hide();
}
And then for testing purposes, I created a form that shows the drop-down UserControl on command:
public partial class Form1 : Form
{
private UserControl1 customDropDown;
public Form1()
{
InitializeComponent();
// Create the user control
customDropDown = new UserControl1();
// Add it to the form's Controls collection
Controls.Add(customDropDown);
customDropDown.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
// Display the user control
customDropDown.Show();
customDropDown.BringToFront(); // display in front of other controls
customDropDown.Select(); // make sure it gets the focus
}
}
Everything works perfectly with the above code, except for one thing: if the user clicks on a blank area of the form, the UserControl doesn't close. Hmm, why not? Well, because the form itself doesn't want the focus. Only controls can get the focus, and we didn't click on a control. And because nothing else stole the focus, the Leave event never got raised, meaning that the UserControl didn't know it was supposed to close itself.
If you need the UserControl to close itself when the user clicks on a blank area in the form, you need some special case handling for that. Since you say that you're only concerned about clicks, you can just handle the Click event for the form, and set the focus to a different control:
protected override void OnClick(EventArgs e)
{
// Call the base class
base.OnClick(e);
// See if our custom drop-down is visible
if (customDropDown.Visible)
{
// Set the focus to a different control on the form,
// which will force the drop-down to close
this.SelectNextControl(customDropDown, true, true, true, true);
}
}
Yes, this last part feels like a hack. The better solution, as others have mentioned, is to use the SetCapture function to instruct Windows to capture the mouse over your UserControl's window. The control's Capture property provides an even simpler way to do the same thing.
Technically, you'll need to p/invoke SetCapture() in order to receive click events that happen outside of your control.
But in your case, handling the Leave event, as #Martin suggests, should be sufficient.
EDIT: While looking for an usage example for SetCapture(), I came across the Control.Capture property, of which I was not aware. Using that property means you won't have to p/invoke anything, which is always a good thing in my book.
So, you'll have to set Capture to true when showing the dropdown, then determine if the mouse pointer lies inside the control in your click event handler and, if it doesn't, set Capture to false and close the dropdown.
UPDATE:
You can also use the Control.Focused property to determine if the control has got or lost focus when using a keyboard or mouse instead of using the Capture with the same example provided in the MSDN Capture page.
Handle the Form's MouseDown event, or override the Form's OnMouseDown
method:
enter code here
And then:
protected override void OnMouseDown(MouseEventArgs e)
{
if (!theListBox.Bounds.Contains(e.Location))
{
theListBox.Visible = false;
}
}
The Contains method old System.Drawing.Rectangle can be used to indicate if
a point is contained inside a rectangle. The Bounds property of a Control is
the outer Rectangle defined by the edges of the Control. The Location
property of the MouseEventArgs is the Point relative to the Control which
received the MouseDown event. The Bounds property of a Control in a Form is
relative to the Form.
You are probably looking for the leave event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
Leave occurs when the input focus leaves the control.
I just wanted to share this. It is probably not a good way of doing it that way, but looks like it works for drop down panel that closes on fake "MouseLeave", I tried to hide it on Panel MouseLeave but it does not work because moving from panel to button leaves the panel because the button is not the panel itself. Probably there is better way of doing this but I am sharing this because I used about 7 hours figuring out how to get it to work. Thanks to #FTheGodfather
But it works only if the mouse moves on the form. If there is a panel this will not work.
private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
{
item_panel1.Visible = true; //Menu Panel
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!item_panel1.Bounds.Contains(e.Location))
{
item_panel1.Visible = false; // Menu panel
}
}
I've done this myself, and this is how I did it.
When the drop down is opened, register a click event on the control's parent form:
this.Form.Click += new EventHandler(CloseDropDown);
But this only takes you half the way. You probably want your drop down to close also when the current window gets deactivated. The most reliable way of detecting this has for me been through a timer that checks which window is currently active:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
and
var timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, args) =>
{
IntPtr f = GetForegroundWindow();
if (this.Form == null || f != this.Form.Handle)
{
CloseDropDown();
}
};
You should of course only let the timer run when the drop down is visible. Also, there's probably a few other events on the parent form you'd want to register when the drop down is opened:
this.Form.LocationChanged += new EventHandler(CloseDropDown);
this.Form.SizeChanged += new EventHandler(CloseDropDown);
Just don't forget to unregister all these events in the CloseDropDown method :)
EDIT:
I forgot, you should also register the Leave event on you control to see if another control gets activated/clicked:
this.Leave += new EventHandler(CloseDropDown);
I think I've got it now, this should cover all bases. Let me know if I'm missing something.
If you have Form, you can simply use Deactivate event just like this :
protected override void OnDeactivate(EventArgs e)
{
this.Dispose();
}

Categories

Resources