Why isn't my UserControl keeping its initialization? - c#

I have a UserControl for which I think I'm initializing some of the members:
// MyUserControl.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyNamespace
{
public partial class MyUserControl : UserControl
{
private string m_myString;
private int m_myInt;
public string MyString
{
get { return m_myString; }
set { m_myString = value; }
}
public int MyInt
{
get { return m_myInt; }
set { m_myInt = value; }
}
public MyUserControl()
{
InitializeComponent();
MyString = ""; // was null, now I think it's ""
MyInt = 5; // was 0, now I think it's 5
}
// .........
}
}
When I insert this control into my main form, though, and call a function that checks values within MyUserControl, things don't look like they're initialized:
// MainForm.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace MyProgram
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void MyButton_Click(object sender, EventArgs e)
{
// this prints 0 rather than 5
MessageBox.Show(this.theUserControl.MyInt.ToString());
}
}
}
I'm guessing this is a really simple error but I don't know where. I've tried prepending this. to things, but this probably isn't the way to go about fixing code. :)
Thanks as always!
EDIT: Stepping into the designer code as Pete suggested showed me where the write-over was happening. First I called the constructor of the user control, and then later, the values got overwritten with default values. I hadn't specified any default values (Sanjeevakumar Hiremath's suggestion) so the default values were those of the primitive types (for int this was 0).

What you're likely seeing here is an artifact of the designer. If you ever opened up MainForm in a designer after you added MyUserControl it likely recorded the default values of MyUserControl in the generated InitializeComponent method of MainForm. These recorded values are re-assigned after the constructor of MyUserControl runs hence they're overwriting the values you set.
You can control this behavior via the use of the DesignerSerializationVisibilityAttribute
http://msdn.microsoft.com/en-us/library/system.componentmodel.designerserializationvisibilityattribute.designerserializationvisibilityattribute.aspx#Y375

Use [DefaultValue] Attribute. It lets you specify default value for a property of a control when the value is not specified in the designer.

Related

Functions inside a static class need the name of the class to be called

I have a class named MyFillerClass in the file MyFillerClass.cs like so :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace trial
{
public static class MyFillerClass
{
public static List<string> returnCategoryNames()
{
List<string> catNames = new List<string>();
catNames.Add("one");
catNames.Add("two");
catNames.Add("three");
catNames.Add("Others");
return catNames;
}
}
}
now when i want to call it from somewhere else (like a form class) :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace trial
{
public partial class Form1 : Form
{
static string lastSelectedCategory;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
listBox1.DataSource = returnCategoryNames(); //error : The name 'returnCategoryNames' does not exist in the current context
lastSelectedCategory = listBox1.SelectedValue.ToString();
}
private void listBox1_SelectedValueChanged(object sender, EventArgs e)
{
lastSelectedCategory = listBox1.SelectedValue.ToString();
System.Diagnostics.Debug.Print("### User choosed " + lastSelectedCategory + " category");
}
}
}
the line "listBox1.DataSource = returnCategoryNames();" produce an error as indicated in the code ,to fix it i have to adjust it to "listBox1.DataSource = MyFillerClass.returnCategoryNames();".
the question is : in a long program that can add a lot of typing ,can i adjust the class MyFillerClass in such a way that i can just call the function like so : returnCategoryNames() ?
No, not in C# up to 5.0. You need to prefix the static method name with the class name.
However, in C# 6.0 there will be static using statements available. This new language feature will allow you to access directly static classes methods.
Yo can't do it in C# yet. To do it, you need to do a none static class and none static method.
You can do an extension method.
To call a function from a class you need to have an object created for that class then only you can call the method defined in the class.
In case of static class no need to create any object. you have to direct call the method followed by the class name.
In your case
MyFillerClass.returnCategoryNames();

Control does not exist in current context

I'm sure this is something simple that I am just overlooking, but I can't figure it out. I am new to C# and I'm trying to create a calculator application. I have created my form with all of my buttons/textbox on it. Now I'm creating a new class to handle all of my methods and whatnot. My problem is that whenever I'm trying to reference controls on the form in the second class, I get the "does not exist in the current context" error. How can I solve this?
An example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public class Calculator
{
decimal currentValue = Decimal.Parse(displayValue.text);
}
}
displayValue receives the error. Thank you for any help.
The Controls can be called only from the .cs file which is linked with the form controls.
What you can do is create a parameterized constructor of your Calculator class like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public class Calculator
{
public Calculator(string displayValue)
{
decimal currentValue = Decimal.Parse(displayValue);
}
}
}
Now, you can call this class in the form .cs where you have buttons and textboxes like this:
Calculator calculate = new Calculator(displayValue.Text);
When you create a new Windows Form Application, there's a designer (which you can interact with to add your buttons and textboxes) and the code-behind (a .cs file).
This .cs file is a partial class, meaning it is also defined by the form you are interacting with. (you can see the nitty gritty details in your .Designer.cs file)
Once you name your buttons and textboxes, you can refer to their names in the code in your partial class!
And when you compile this, your button text will change to "Hello World!"
Hope this helps.
You will find this control in partial class of the form. You can take values from it and do your operation
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string s = textBox1.Text;
}
}

An object reference is required for the non-static field, method, or property 'WindowsFormsApplication1.Form1.label1'

I want to reuse a piece of code, so I figured I'll make a class with a method that contains that code, and then I'll just call the method wherever I need it.
I've made a simple example of what my problem is:
Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
LoadText.getText();
}
}
}
LoadText.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApplication1
{
public class LoadText : Form1
{
public static void getText()
{
WindowsFormsApplication1.Form1.label1.Text = "New label1 text";
}
}
}
As you can see I've got one form with a label, and I want to use my other method (getText in LoadText) to change the text of the label.
Here's my error message:
An object reference is required for the non-static field, method, or property 'WindowsFormsApplication1.Form1.label1'**
I've already changed label1 from private to public under design.
How can I fix this problem?
The problem is that Form1 is a class, not an object. label1 is not a static member of the class, it is a member of the instance of Form1. Hence the error, which tells you that an object instance (of the Form1 class) is required.
Try the following:
Form1.cs:
LoadText.getText(label1);
LoadText.cs:
public static void getText(Label lbl)
{
lbl.Text = "New label1 text";
}
You now have a static method that will accept a Label object and set its text to "new label1 text".
See the following link for further information on the static modifier:
http://msdn.microsoft.com/en-us/library/98f28cdx.aspx
HTH
This is a common problem for newcomers to OO programming.
If you want to use a method of an object, you need to create an instance of it (using new). UNLESS, the method doesn't require the object itself, in which case it can (and should) be declared static.
I tried a different method that worked also:
Form1.cs:
// here a static method is created to assign text to the public Label
public static void textReplaceWith(String s, Label label)
{
label.Text = s;
}
LoadText.cs:
namespace WindowsFormsApplication1
{
public class LoadText : Form1
{
//new label declared as a static var
public static Label pLabel;
//this method runs when your form opens
public LoadTextForm()
{
pLabel = Label1; //assign your private label to the static one
}
//Any time getText() is used, the label text updates no matter where it's used
public static void getText()
{
Form1.textReplaceWith("New label1 text", pLabel); //Form1 method's used
}
}
}
This will allow you to use a public method to change the text variable for your label from just about anywhere. Hope this helps :)
You need a reference to your form in order to access its elements.

Most efficient way to call/access windows form controls in a class

I added a CSharp Class to a form project. Now I want to access the form controls from the Class.
I am using this piece of code with the implicit var as follows:
var form = frmClasses.ActiveForm as frmClasses;
Using this code, I set the form Modifiers to public, place the code is a method/function and I am able to access the form controls in the class.
The problem is each time I need to call a form control I have to use the var and the entire line of code above. Is there a simpler way that is less redundant?
Example: Each method/function in a the class will need to call the form controls thus referencing the form controls using Var.
Take a look at the code below, you will noticed that I am using Var to call each form control.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace Classes
{
class ClsProperties
{
//VALIDATE TEXTBOX
public static void validateTextBox()
{
var form = frmClasses.ActiveForm as frmClasses;
if (form.txtMyTextBox.Text.Trim().Length == 0)
{
form.txtMyTextBox.BackColor = Color.Aquamarine;
}
}
//VALIDATE RADIO BUTTON
public static void validateRadio()
{
var form = frmClasses.ActiveForm as frmClasses;
if (form.radBtnColor.Checked == false)
{
form.lblShowError.ForeColor = Color.Aquamarine;
}
}
}
}
Form Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Classes
{
public partial class frmClasses : Form
{
public frmClasses()
{
InitializeComponent();
}
private void btnSubmit_Click(object sender, EventArgs e)
{
ClsProperties.validateRadio();
ClsProperties.validateTextBox();
}
}
}
I could put all the validation in one method but I am simply trying to show how I would call multiple methods using a class.
Is there a better way to access the form elements in a class?
Merci

Show/Hide panel of parent control

I have a base class inheriting from UserControl on which there is a panel. I made a property that allows me to show/hide the panel.
public partial class BaseControl : UserControl
{
// ...
private Panel panTitle; // this is actually declared in the designer file..
public BaseControl()
{
InitializeComponent();
// hide the panel by default
IsTitlePanelVisible = false;
}
[DefaultValue(false)]
public bool IsTitlePanelVisible
{
get { return panTitle.Visible; }
set { panTitle.Visible = value; }
}
}
Now if I open some other control inheriting from BaseControl in the designer, the panel is visible!
After I change the IsTitlePanelVisible property to true and back to false in the property window, it disappears.
I also set the Visible property of the panel itself to false in the designer of BaseControl, but it still shows up.
Has anyone some advice on how to get the panel to not show up when opening a derived control in the designer?
Edit: To make things clearer, there's the following addition:
I already have a quite large number of derived controls and I don't want to change all of them.
If I open a derived control and manually set the value to false, everything works fine, but I can't understand why it wouldn't work since the value is set to false in the base control's constructor..
Perhaps you need to invoke the base constructor
class DerivedControl : BaseControl
{
public DerivedControl()
: base()
{
}
}
class BaseControl : UserControl
{
public BaseControl ()
{
InitializeComponent(); // makes the panel visible by default
IsTitlePanelVisible = false // makes the panel hidden explicity
}
}
Also from MSDN :
A DefaultValueAttribute will not cause a member to be automatically
initialized with the attribute's value. You must set the initial value
in your code.
I made a quick test application to see if I could duplicate your problem. The only thing that I did differently was to add the panel in the designer and set its visibility to false. It worked correctly doing that. It looks like you are creating the panTitle Panel manually. Where/When are you adding it to your control, your best bet would be to add the Panel like I stated above.
Edit:
In reading your question a little closer, it seems like you are not wanting the Panel to showup when you are looking at the DerivedUserControl's Design Tab. What I have posted will not change that, I am not sure if that behavior can be changed. It will not be visible when you drop it on a Form though and in that way acts like expected.
Here is a quick working example.
Form1
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
DerivedUserControl dv = new DerivedUserControl();
public Form1()
{
InitializeComponent();
this.Controls.Add(dv);
}
private void button1_Click(object sender, EventArgs e)
{
if (dv.IsTitlePanelVisible)
dv.IsTitlePanelVisible = false;
else
dv.IsTitlePanelVisible = true;
}
}
}
Base UserControl
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class BaseControl : UserControl
{
public BaseControl()
{
InitializeComponent();
}
[DefaultValue(false)]
public bool IsTitlePanelVisible
{
get { return panTitle.Visible; }
set { panTitle.Visible = value; }
}
}
}
BaseControl.Designer.cs InitializeComponent
private void InitializeComponent()
{
this.panTitle = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// panTitle
//
this.panTitle.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(255)))));
this.panTitle.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.panTitle.Location = new System.Drawing.Point(0, 0);
this.panTitle.Name = "panTitle";
this.panTitle.Size = new System.Drawing.Size(150, 147);
this.panTitle.TabIndex = 0;
this.panTitle.Visible = false;
//
// BaseControl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panTitle);
this.Name = "BaseControl";
this.ResumeLayout(false);
}
Derived UserControl
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class DerivedUserControl : BaseControl
{
public DerivedUserControl()
{
InitializeComponent();
}
}
}
Have you tried setting panTitle.Visible to false by default?
the ComponentModel DefaultValue attribute is only used for the designer to determine whether the property in the propertyGrid should be shown as bold (dirty) and whether its value should be generated to the InitializeComponent method of derived classes of the BaseControl

Categories