Winform & user control - C# - 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?

Related

Access UI form controls from another class into your main form in C#

How can I use my UI form controls from another class? I want to work with these controls in another class, then call it into my main form. The problem is that the new class I created can't seem to access the label or the textboxes of these controls and I keep getting an error.
How would i solve this issue?
Error Messages:
FirstName_text is inaccessible due to its protection level
First_Name_label is inaccessible due to its protection level
Color does not exist in the current context
public void Checker()
{
//First Name Validation
if (Regex_Static_Class.FirstNameRgex.IsMatch(FirstName_text.Text) == false)
{
First_Name_label.Text = "invalid first name";
Error_Lable.ForColor = Color.Pink;
}
}
I guess First_Name_label is a UI label and it must be accessible form your other class too.
Maybe make a setter method to fill in text into your label.
I would say that you have to set Modifiers property for your controls to public or internal in Forms Designer to access it from another class. Control's instance is protected by default.
That's the answer to your question. Another thing is that it's not the best idea to do that. You shouldn't access form's controls outside of form directly. Form class should encapsulate its controls and expose an interface to change them, for example.
Also Color doesn't exists most probably because you don't have proper using in your another class.
It has nothing to do with conditions (references to conditions removed from the original question).

Accessing ParentForm from child and ensuring the child is added

I have code that dynamically loads (and destroys) user controls of different types onto a form as they are needed. The user control uses properties from its parent to load certain values into controls such as textboxes and check boxes. The issue is that in the line:
activeControl = new userControl1(params...);
my constructor is obviously going to try loading fields that don't exist yet (they belong to the parent form) since it hasn't been added to the parent form until after userControl1 is created.
I tried solving this using the ParentChanged event of the user control so it waits until its parent is set before loading fields. The problem here is when I destroy userControl1 and create a userControl2, the parent changes and it tries to load the fields from the null ParentForm (the exact problem I had originally.
Is there a preferred way to tackle this? Clearly, I could just add something like
if(this.ParentForm == null) { return; }
to the ParentChanged event or something along those lines. But this feels neither elegant nor safe. Am I overlooking some event or preferred way to accomplish this?
While it is not necessarily bad to check for null references and divert the code accordingly (e.g. not try to reference a missing object), the better approach here is to decouple your UserControl classes from their parents.
That is, these UserControl classes should not have any awareness of their parent form types at all. To do otherwise is to negate one of the major benefits of OOP: code reuse. With your current design, even if you get it to work without crashing, you can't ever use these UserControl objects except in the context of this specific parent form type.
You may think today that that's okay, that you'll never want to use them in any other context. But the future is hard to predict. You may decide, for example, that you want a variation on the parent form that should still use these same UserControl objects.
What you should be doing is exposing the UserControl state via public properties, and then allow the parent form to initialize those as necessary.
Here's a very simple example (I'm omitting the Designer-created code…I assume that you can infer from the field names what I mean):
partial class UserControl1 : UserControl
{
/* ... */
public bool IsMyFlagChecked
{
get { return checkBox1.Checked; }
set { checkBox1.Checked = value; }
}
/* ... */
}
partial class ParentForm : Form
{
/* ... */
private void SomeMethodThatAddsUserControl1()
{
UserControl1 uc1 = new UserControl1;
uc1.IsMyFlagChecked =
this.SomeParentFormPropertyUserControl1UsedToReferenceDirectly;
// other initialization for uc1...
Controls.Add(uc1);
}
/* ... */
}
(Note that without a good, minimal, complete code example that illustrates your question, I can't provide a more detailed code example than the above. If this doesn't seem to address your question, please edit it so that it provides more detail, including a better code example).

How can I access one Windows Forms control from another Windows Forms?

Suppose I create a window form Form.cs. It has some controls(label1, label2, button1, button1 etc.). I also create a new window form New_Form.cs under Form.cs. Now I want to access label1, label2, button1 in New_Form.cs. How can I do this?
I don't want to be offensive, but I think that using control from another form is not a good design.
In my oppinion it is not good to couple one class (in this question form1) to the inner implementation of another class (controls of `form2´. If you, for some reason, have to change the inner design (e.g. showing the data with a different control) of that class, you have to change the other class too. That makes coding (and of course error searching) quite difficult.
If there is a need to exchange data between two classes, I would prefer using publioc Properties for that. In the inner design you can attach them to a control, but then this "coupling" stays in the same class)
Although this can be bad design, you can access properties in another Form by making them public and then accessing them like this:
Form1 frm = new Form1();
Form1.button1.Visible = false;
Also here is an msdn page pertaining to your question
http://msdn.microsoft.com/en-us/library/f6525896%28v=vs.90%29.aspx
You can access the required properties by setting them as public properties in your Parent form. Not sure as why you would want the button, if you want some thing to be executed for the click then you should encapsulate the logic into separate methods and them make the call.
If you have fewer details to pass then make constructors for the new form which would accept those values
ChildForm child = new ChildForm([label1], [label2])
or
ChildForm child = new ChildForm([parent form reference]) // so you could access require components

.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.

Calling Methods from seperate usercontrols in the same form

I really had no idea what to title this question.
Assume I have a windows form application. The GUI is complex enough to require two custom user controls, "LeftSide" and "Rightside" which each are composed from various buttons, labels, and maybe even another custom user control.
My question:
I am in in the scope of the "Rightside" control. How would I call a method from the "Leftside" control?
I am using Visual Studio 2008.
The simplest solution is to make a property on the RightSide control of type LeftSide, then set it to the LeftSide instance in the form designer.
You can then call public methods on the property.
However, this is poor design.
Each usercontrol should be a self-contained block that doesn't need to directly interact with other usercontrols.
You should consider restructuring your form.
Exact equivalent with standard WF controls: how to keep the text of one text box in sync with another:
private void textBox1_TextChanged(object sender, EventArgs e) {
textBox2.Text = textBox1.Text;
}
Necessary ingredients: an event on your user control that is fired when something interesting happens. And public properties.

Categories

Resources