Why do CausesValidation does not propagate from Containers to child controls? - c#

I am using c#.
Why does the CausesValidation property does not propagate from containers to child controls?
I have a TabControl and i need to perform validation of user input on all tabs.
But each tab is independent. I found out that if i have a container like a TableLayoutPanel and i set CausesValidation to false, the child componentes still perform validation.
So this code would not work:
Foreach(Control c in Container.Controls)
{
c.CausesValidation = False;
}
If you do some DEBUG output you will see that the only found control is the TableLayoutPanel or any other container like a GroupBox that will be found and set to False. But containers are not propagating that value to the child level.
A lot of people asked how we could solve the problem. I found a lot of methods, but i have created a static class that allows me to select wich tab on the TabControl that i want to perform validation, and it will set CausesValidation to False on ALL controls of that TabControl, including child controls with a deepness of 10 layers. If you want that library just ask for it!
My real question is, should not a container propagate that property to its child controls, and that child controls to any child controls?!
It would save us a lot of work from creating a very crazy code that is very specific for something that should work from scratch? Why is this not implied?

This just isn't a constructive way to deal with your requirement. The feature just wasn't implemented the way you like it to work and that's never going to change. It isn't a problem, you can easily add it yourself with a wee bit of code:
public static void SetCausesValidation(Control.ControlCollection ctls, bool enable) {
foreach (Control ctl in ctls) {
ctl.CausesValidation = enable;
SetCausesValidation(ctl.Controls, enable);
}
}
And use it in your form constructor, something like:
public Form1() {
InitializeComponent();
SetCausesValidation(panel1.Controls, false);
}
Note the use of recursion in the method to set the property through the entire tree of controls inside the container.

Related

Recommended way to manipulate User Control panels into a Windows From

I just started working with Visual Studio C# and to be honest I didn't fully understand what happens when we chose to hide a form or a user control.
My intuition tells me this hide/show method is kind of "inefficient" way to get an user through all the functions of my app.
So I am asking you guys if there is another workaround to "load" user control parts in a form.
Right now my main_menu form has all the user control objects placed on the form, but hidden, and I am using buttons to show them.
Is there a better way to achieve the same result? (I was thinking of a workaround like having an empty panel where I can load the User Control - not sure if possible)
Thank you!
You can create the controls on the fly and add them to or remove them from the Controls collection. On the class level, define this field
private Control _currentPanel;
You can use a more specific type here, if you are deriving all your panels from a common base type.
Then change the panel with
// Remove previous one.
if (_currentPanel != null) {
Controls.Remove(_currentPanel);
}
// Add new one
_currentPanel = new MyNewPanel();
//TODO: possibly set the panels Docking property to Fill here.
Controls.Add(_currentPanel);
In the example I am working with the form's Controls collection; however, you might have to use the Controls collection of some container control holding the panel.

Invoke form controls (Better than mine) [duplicate]

What is the preferred/easiest way to find the control that is currently receiving user (keyboard) input in WinForms?
So far I have come up with the following:
public static Control FindFocusedControl(Control control)
{
var container = control as ContainerControl;
return (null != container
? FindFocusedControl(container.ActiveControl)
: control);
}
From a form, this can be called simply as (in .NET 3.5+ this could even be defined as an extension method on the form) -
var focused = FindFocusedControl(this);
Is this appropriate?
Is there a built-in method that I should be using instead?
Note that a single call to ActiveControl is not enough when hierarchies are used. Imagine:
Form
TableLayoutPanel
FlowLayoutPanel
TextBox (focused)
(formInstance).ActiveControl will return reference to TableLayoutPanel, not the TextBox (because ActiveControl seems to only be returning immediate active child in the control tree, while I'm looking for the leaf control).
If you have other calls to the Windows API already, there's no harm in using Peters solution. But I understand your worries about it and would tend to a similar solution as yours, using only the Framework functionalities. After all, the performance difference (if there is one) shouldn't be significant.
I would take a non recursive approach:
public static Control FindFocusedControl(Control control)
{
var container = control as IContainerControl;
while (container != null)
{
control = container.ActiveControl;
container = control as IContainerControl;
}
return control;
}
After searching the Internet, I found the following on George Shepherd's Windows Forms FAQ
The .Net framework libraries does not provide you an API to query for
the focused Control. You have to
invoke a windows API to do so:
[C#]
public class MyForm : Form
{
[DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.Winapi)]
internal static extern IntPtr GetFocus();
private Control GetFocusedControl()
{
Control focusedControl = null;
// To get hold of the focused control:
IntPtr focusedHandle = GetFocus();
if(focusedHandle != IntPtr.Zero)
// Note that if the focused Control is not a .Net control, then this will return null.
focusedControl = Control.FromHandle(focusedHandle);
return focusedControl;
}
}
ActiveControl on a Form or Container will return that entity's active control no matter how deeply it might be nested inside other containers.
In your example if the TextBox has Focus : then : for Form, TableLayoutPanel, and FlowLayoutPanel : the 'ActiveControl property of all of them will be the TextBox !
Some, but not all, "genuine" ContainerControl types ... like Form and UserControl ... expose Key Events (in the case of Form : only if Form.KeyPreview == true can they be used) .
Other controls which, by design, contain other controls like TableLayOutPanel, GroupBox, Panel, FlowLayoutPanel, etc. are not type ContainerControl, and they do not expose KeyEvents.
Any attempt to cast instances of objects like TextBox, FlowLayoutPanel, TableLayoutPanel directly to ContainerControl will not compile : they are not type ContainerControl.
The code in the accepted answer, and in the next answer that corrects the first answer's spelling errors, will compile/accept instances of the above as parameters because you are "downcasting" them to type 'Control by making the parameter type 'Control
But in each case the cast to ControlContainer will return null, and the passed in instance will be returned (downcasted) : essentially a no-op.
And, yes, the modified answer code will work if you pass it a "genuine" ControlContainer, like a Form instance, which is in the parent inheritance path of the ActiveControl, but you are still just wasting time duplicating the function of 'ActiveControl.
So what are "genuine" ContainerControls : check them out : MS docs for ContainerControl
Only the answer by Peter really answers the explicit question, but that answer carries the price of using interop, and 'ActiveControl will give you what you need.
Also note that every Control (container or non-container) has a Controls Collection that is never null, and that a lot of (I've never tried all of them : why would I ?) the basic WinForms control let you do "crazy stuff" like adding Controls to the ControlCollection of 'simple' controls like Button without an error.
Now if the real intent of your question was to ask how you find the outermost ContainerControl ... that is not on the Form itself ... of a regular non-container Control nested some arbitrary levels deep ... you can use some of the ideas in the answer : but the code can be greatly simplified.
Regular Controls, ContainerControls, UserControls, etc. (but not Form !) all have a 'Container property you can access to get their immediate container, but making sure you have the 'final Container in their inhertance path that's not a Form requires some code to "walk-up" the inheritance tree, which is demonstrated here.
You may also wish to check out the 'HasChildren property of 'Control which is usually useful in dealing with issues of Focus, ActiveControl, and Select in WinForms. Reviewing the difference between Select and Focus can be valuable here, and SO has some good resources on that.
Hope this helps.
Hinek's solution works well for me, except it is ContainerControl, not ControlContainer. (Just in case you were scratching your head about that red squiggly line.)
public static Control FindFocusedControl(Control control)
{
ContainerControl container = control as ContainerControl;
while (container != null)
{
control = container.ActiveControl;
container = control as ContainerControl;
}
return control;
}
If you follow ActiveControl out recursively it doesn't take you to the leaf control that has focus?
ActiveControl doesn't always work out, like with SplitContainer, ActiveControl.Focused is false.
So for a more fool proof method could do something like this:
private IEnumerable<Control> _get_all_controls(Control c)
{
return c.Controls.Cast<Control>().SelectMany(item =>
_get_all_controls(item)).Concat(c.Controls.Cast<Control>()).Where(control =>
control.Name != string.Empty);
}
var _controls = _get_all_controls(this);
foreach (Control control in _controls)
if (control.Focused)
{
Console.WriteLine(control.Name);
break;
}

What is the proper way to access Controls properties of User Controls in Winform?

I created this User Control:
I added that User Control to the main Form and now I want to customize it.
So I will have to add text to those 3 Buttons, text in Label, populate ListBox and setting Click Events for the buttons.
What is the proper way to do that?
I looked around on the web and apparently the way to do it is to add public properties in user control that would expose individual property of control that I need.
Something like:
public string Button1Text
{
get
{
return btn1.Text;
}
set
{
btn1.Text = value;
}
}
If I go this route, I would have to add quite a few public properties to this simple user control.
But isnt it easier just to expose whole control in user control like this?
public Button MyButton1
{
get { return this.btn1; }
set { this.btn1 = value; }
}
That way the Main Form can simply access control and its properties as they are needed.
First method is better from the perspective of encapsulation. Second method causes users (forms) of your control to depend on the view of your control, and this prevents changes to the view in the future.
The first bit of code is the correct way to do it. You will have to create a lot of them but it is the proper way to do it.
The first one is much better where you only create properties for each individual property of the button you wish to be able to access from the Parent control.
If you use the second way, then anyone who wishes to use your control will be able to move and resize individual controls inside your control. Then it really isn't a custom control anymore, but more of a panel that is harder to use than a panel. I can't think of any reason why to be able to allow the Parent to move around individual elements in a subcontrol.

Specify properties from baseform towards inherited ones

I have a c# winform that is a template for all the forms in my project.
My problem is how do I setup some properties for the controls that will be added in the inherited forms from the baseform.
For example I want all the textboxes that will be in the forms to have a specific color, or call an extension method.
Right now I tried the simple idea that popped out:
foreach (Control c in Controls)
{
if(c is ComboBox)
{
//do something
}
if(c is TextBox)
{
//do something
}
}
I put this code in the base form load event, but with no luck. I tried changing the modifiers from the inherited form to protected, but with no luck.
Is there any solution to this problem? Or I am obliged to put this code in all of my forms that inherit baseForm?
Custom Controls are the solution to the problem you have at hand. Simply extend existing Controls to have attributes of your desire and then you could these controls in all of your Forms.
You're beginning to think along the right lines, but you're not quite there yet. The solution to this problem is definitely object-oriented inheritance, but you must be careful not to violate other important principles of OOP, namely encapsulation.
To put things a different way, the form should not be required to "know" about the properties of the controls that it contains. It shouldn't know or care that it contains a ComboBox or a TextBox or a ListView.
Instead, you should subclass each of the child controls that you want to modify, and set their default properties there. Then, you would just add an instance of your custom subclassed control to your form, rather than the built-in control.
So, for example, your custom TextBox class might look like this:
public class CustomTextBox : TextBox // inherit from TextBox
{
public CustomTextBox()
{
// default constructor
}
// other logic...
}

winforms panels vs java swing panels

In java swing I can insert panels into panels and so on, and not have to build a brand new window for every view of my applicaiton, or mess around removing and adding controls.
Theres a panel clas sin C# however I cant see any way of creating a 'panel form' or basically just a form in form designer thats a panel and its contents.
How do I do this then and work the way I did with java swing?
Usually i just dock different forms within eachother setting the IsMdiContainer Property to true on the parent window. Then i create subforms that i dock using the following function:
static class FormUtil
{
static public void showForm(Form sender, Control reciever)
{
sender.ControlBox = false;
sender.FormBorderStyle = FormBorderStyle.None;
sender.ShowInTaskbar = false;
sender.TopLevel = false;
sender.Visible = true;
sender.Dock = DockStyle.Fill;
reciever.Controls.Clear(); //clear panel first
reciever.Controls.Add(sender);
}
}
then whenever i need to dock a form inside a panel on the parents form i just do:
FormUtil.showForm(new SomeForm(), this.splitContainer1.Panel1);
This allows me to delegate some of the form creation to different designers. Works like a charm for me, love to hear if theres a better way of doing it.
Actually, you can use the panel control and set it's Dock property to Fill. That way, your panel will be the entire canvas of the form. Then, you can add child panels as needed either through code behind or through forms designer.
There's the concept of user controls which basicly provides you with a panel like designer surface , not to mention that you can create atomic forms (which can be reused) and register them as inheritable, that way you can provide inheritance too.

Categories

Resources