Currently I have multiple classes, one of which is called the 'Variable class' where I
{get;set;}
my values obtained from other classes. Accessing these values in voids is simply:
Private void (Variables vb)
{
}
However in the 'Load' part of Winforms,
private void Form1_Load(object sender, EventArgs e)
{
}
From the Variables Class:
public class Variables
{
public int Node { get; set; }
}
The object sender, EventArgs e part is occupying the space where I place the arguments. Is there any way that I could obtain Node from the class Variableson the winform?
Your method Form1_Load is an event handler (because it usually gets called as a result of some event occurring). The "Load" event is defined by WinForms, so you cannot change the fact that the arguments are object sender and EventArgs e.
WinForms creates one instance of your Form1 class before it displays your form. Whenever an event happens on your form, the event handler on that same object is called.
So, you can store values in fields and properties of your Form1 class:
public class Form1 : Form
{
Variables _myVariables;
public Form1()
{
InitializeComponent();
_myVariables = new Variables() { Node = 10 }
}
private void Form1_Load(object sender, EventArgs e)
{
MessageBox.Show("The current value of _myVariables.Node is: " + _myVariables.Node);
}
}
If your Variables object is created outside your form, then you can pass it into your Form1 constructor:
public class Form1 : Form
{
Variables _myVariables;
public Form1(Variables variables)
{
InitializeComponent();
_myVariables = variables;
}
// ...
}
// Then, somewhere else:
var variables = new Variables() { Node = 10 };
var myForm = new Form1(variables);
myForm.Show();
// or: Application.Run(myForm);
I'm not 100% sure if this is what you are looking for, but I think I can help.
namespace Example
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//class which can be used anywhere in the namespace
public class exampleClass
{
public const string SETSTATE = "0";
public const string GETSTATE = "1";
public const string SETVALUE = "2";
public const string GETVALUE = "3";
public const string SENDFILE = "4";
public const string STATE_RP = "129";
public const string VALUE_RP = "131";
public const string STATUS_RP = "128";
}
}
}
you can use exampleClass, and any of its enclosed members, anywhere within Form1 here. You do not need to pass it anywhere within the form to use it. You could add a function later that uses it directly like:
void exampleF()
{
//note that when you are accessing properties of UI elements from
//a non-UI thread, you must use a background worker or delegate
//to ensure you are doing so in a threadsafe way. thats a different problem though.
this.txtYourTextBox.txt = exampleClass.GETSTATE;
}
Maybe your attempt is it actually to use MVP-Pattern in WinForms. Very good idea.
Then you can use DataBinding to Bind your Forms-Controls to your "Variables classes" properties. Your variable class takes the presenter role, your form is the view, and your model(s) are the sources of your variable classes data.
Unfortunately, the pattern uses some advanced mechanisms you have to deal with.
For more information, you might take a first look here:
Databinding in MVP winforms
Related
I have a main form which opens a second form as a dialog.
On the dialog form close, I would like to edit an external struct so all the form settings are captured on close.
I pass a struct into the dialog form constructor, but it seems it is copied when I save it to a private property inside the class.
How can I maintain a link to the external struct?
Below is the relevant code for the dialog form.
public partial class MASettingsForm : Form {
private MovingAverageSettings _settings;
public MASettingsForm(ref MovingAverageSettings settings) {
InitializeComponent();
_settings = settings;
SetUI(_settings);
}
public void SetUI(MovingAverageSettings settings) {
maTypeComboBox.SelectedIndex = (int)settings.type;
maCalcMethodComboBox.SelectedIndex = (int)settings.calcMethod;
maCalcValueUpDown.Value = settings.calcPeriod;
maOffsetUpDown.Value = settings.offset;
applyToHeikenAshicheckBox.Checked = settings.useHeikenAshi;
OnTypeChange();
}
// User clicks ok to apply the dialog form settings
private void okBtn_Click(object sender, EventArgs e) {
DialogResult = DialogResult.OK;
_settings.type = (enum_Ma_Type)maTypeComboBox.SelectedIndex;
_settings.calcMethod = (enum_Calculation_Method)maCalcMethodComboBox.SelectedIndex;
_settings.calcPeriod = (int) maCalcValueUpDown.Value;
_settings.offset = (int)maOffsetUpDown.Value;
SetExtendedValues(_settings);
Close();
}
The best you can do is is to introduce a wrapper around the struct:
public class Ref<T>
{
public T Value { get; set; }
public Ref(T value) => Value = value;
}
And instead of trying to pass a ref to the class constructor - pass a Ref<MovingAverageSettings> object.
That way your struct can be immutable, and you would just replace the entire struct when it needs to change. You can also add an event that is raised when the value is set, to let any form know if it needs to update itself to show the updated value.
But I would change your struct to a class, there is a lot of limitations and pitfalls with structs in c#, you can get some information in the article from MS: https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct?redirectedfrom=MSDN
namespace Bus
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
string selectedItem=listBox1.SelectedItem.ToString();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
groupBox1.Text=selectedItem;
}
}
}
When I run this, I get an error for selectedItem in private void saying that selectedItem does not exist in the current context.
Why is that? If I declare the string in public Form2(), shouldn't others be able to use it since it's public?
selectedItem is a local string for your Form2's constructor only. You need to either create it as a field or property for all components of your Form2 class to be able to access it.
define selectedItem as property or field:
namespace Bus
{
public partial class Form2 : Form
{
public string selectedItem {get; private set}
//private string selectedItem;
public Form2()
{
InitializeComponent();
selectedItem=listBox1.SelectedItem.ToString();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
groupBox1.Text=selectedItem;
}
}
}
there are a number of things you need to consider here
firstly any variable created inside a method can only be used inside that method
because of this you need to upgrade it from a local variable to a class variable
secondly how are are going to upgrade it it can be done in several ways
Field : this is generally used to things that are only needed inside the class not outside (though they can be declared public this is not best practice)
eg
public partial class Form2 : Form
{
private string selectedItem;
Property : Properties are used when fields need to be used outside the class or when you need addition control over what happens when data is got or set
eg
public partial class Form2 : Form
{
public string SelectedItem{get;set;}
Static : this is when you need to access the variable from every instance of a class not just the one its set in, static can be either a field or property
eg
public partial class Form2 : Form
{
public static string SelectedItem{get;set;}
which you need is dependent on what you need to accomplish
also just because a class is public doesn't mean everything on it is public,
you might have things on it that are only useful inside the class (private)
only in the class or its descendent (protected)
only inside the project (internal)
or accessible to everything (public)
so you must set the access on each method or property separately (if you don't it will default to internal), properties allow you to set this for both the get and the set separately so you can have a property that anything can read from but only the class itself can change
Well, selectedItem is a local variable and can be used locally only, within the constructor scope in your case. Convert it into property:
namespace Bus
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public String SelectedItem {
get {
if (null == listBox1.SelectedItem)
return "";
return listBox1.SelectedItem.ToString()
}
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
groupBox1.Text = SelectedItem;
}
}
}
You need to make it a class level field
namespace Bus
{
public partial class Form2 : Form
{
private string selectedItem;
public Form2()
{
InitializeComponent();
selectedItem=listBox1.SelectedItem.ToString();
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
groupBox1.Text=selectedItem;
}
}
}
For example after creating a new Windows Form project I have my class called Form1.cs and from that form I can simply start typing the name of a form control and it will auto populate the form control variable names and I am able to use them in the class. However I have other classes that need to be able to access these form control variables as well, but they are not accessible.
Make them public if they are going to be used in another assembly, or internal if they are going to be used in the same project. Making them static means you don't have to pass your Form1 into the other classes.
Example... Say your Form1 has a string that contains the text you display in the title bar. Making it internal static, like this:
internal static readonly string MsgBox_Title = " Best Application Evar!";
lets you access it from other classes like this:
Form1.MsgBox_Title
It doesn't have to be readonly; that's just an example I pulled from an old app...
If you don't want static variables, you'll have to pass in an instance of Form1.
public class SomeClass
{
private Form1 m_Form1;
public SomeClass(Form1 form1)
{
m_Form1 = form1;
}
private void someMethod()
{
string localValue = m_Form1.SomeMemberStringVariable;
}
}
It's a very contrived example, but hopefully you get the idea.
If you want to call the Refresh method from a class instantiated from Form1, you could use an event in the child class to notify Form1.
Example:
This Form1 has a button that I use to show a secondary form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnShowPopup_Click(object sender, EventArgs e)
{
PopupForm f = new PopupForm();
f.CallRefreshHandler += PopupForm_CallRefreshHandler;
f.ShowDialog();
}
private void PopupForm_CallRefreshHandler(object sender, EventArgs e)
{
Refresh();
}
}
The secondary form, "PopupForm", has a button that I use to raise an event that the Form1 is subscribed to, and lets Form1 know to call Refresh.
public partial class PopupForm : Form
{
public event EventHandler CallRefreshHandler;
public PopupForm()
{
InitializeComponent();
}
private void btnRaiseEvent_Click(object sender, EventArgs e)
{
EventHandler handler = CallRefreshHandler;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Hope this helps.
Create an object of that class & start using those variables like this
Form1 fm = new Form1();
string abc = fm.VAR;
Define a public property in your form.
public string MyProp { get; set; }
Form1 frm = new Form1();
frm.MyProp = "Value";
Or define the property as static to avoid having to instantiate Form1:
public static string MyProp { get; set; }
Form1.MyProp = "Value";
I ran into this issue recently. I was keeping some methods in a separate class. Maybe not a good design decision in my case, I'm not sure yet. And these methods sometimes needed to communicate with controls in the main Form1. For example, to write to textBox1.
Turns out easy enough. Just write your method signature to include a TextBox instance. For example you pass textBox1 in and inside the method you refer to it as tb. Then when you call that method (even though it is in another class) you set the tb.Text property to whatever you like and it will show on textBox1.
This makes sense when you consider that control is just a special kind of object, graphically represented in the Form. When you pass it as an argument to a method in another class or the same class, you are actually passing the reference. So writing text to it in the method call will write text to the original control.
I've got a class where I've declared this struct
public struct Tasks
{
public string tName;
public string tDate;
public string tPriority;
public string tDescription;
}
In Form1, I've constructed
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Tasks[] entry=new Tasks[taskName.Length];
}
}
This works fine and dandy, but I want to use entry struct one a button press.
private void TaskName1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2(entry[i].tDate, entry[i].tName, entry[i].tPriority);
frm.Show();
}
It obviously gives the warning "The name "entry" does no exist in the current context".
I'm fairly new to programming, but I have spent a few hours trying many things to no avail.
I've tried finding ways to make the entry[array] public somehow.
I've created public class and declared the struct and construct public, but still I couldn't get it to work.
I wanted to use the entry struct to send to another form because that's where I hold information and I will use the struct to write to ext files.
Any solutions or better ways to do this?
How can I use a struct across multiple forms, classes, etc.? Basically anywhere.
You keep your Tasks array inside the constructor of your form. So it's visible only within the scope of the constructor. To make it visible for other Form1 members it has to be declared on the level of your Form1 class:
public partial class Form1 : Form
{
Tasks[] entry;
public Form1()
{
InitializeComponent();
entry = new Tasks[taskName.Length];
}
}
This is only to make your syntax correct. Whether your approach is worth pursuing is entirely different question and I strongly advise you to read through the comments to your question.
You're attempting to reference a local variable declared in the constructor in a method that knows nothing about this variable. C# has a concept called "scope", in which variable declarations are only accessible by the block of code that creates them. ie. If you declare a variable inside method MyMethod(), you can only directly access it inside MyMethod(). Scopes can be nested, too, with any nested scope being able to access any variables in the parent scope, but not vice-versa. For example:
class MyClass {
int someInt = 0;
void MyMethod() {
int anotherInt = 5;
someInt += 1; // This works, as someInt was declared as a class-wide variable.
}
void AnotherMethod() {
anotherInt = 6; // Will not work! anotherInt was declared in MyMethod, so is in a separate scope than that of AnotherMethod.
string aString = "asd";
if (someInt == 0) { // Again, this works because this variable is declared in the parent scope.
string anotherString = "fgh";
aString = "asdasd"; // Works
}
anotherString = "oh no"; // Does not work, because if-statements create their own scope!
}
}
Basically, every time you see an opening curly brace ( { ), you know that a new scope is being created.
Move the declaration outside of the Form1() constructor, and just define it in the constructor.
public partial class Form1 : Form {
Tasks[] entry;
public Form1() {
InitializeComponent();
entry = new Tasks[taskName.Length];
}
}
You can then reference entry from any methods inside Form1.
Although there are some similar questions I’m having difficulties finding an answer on how to receive data in my form from a class.
I have been trying to read about instantiation and its actually one of the few things that does make sense to me :) but if I were to instantiate my form, would I not have two form objects?
To simplify things, lets say I have a some data in Class1 and I would like to pass a string into a label on Form1. Is it legal to instantiate another form1? When trying to do so it looks like I can then access label1.Text but the label isn’t updating. The only thing I can think of is that the form needs to be redrawn or there is some threading issue that I’m unaware of.
Any insight you could provide would be greatly appreciated.
EDIT: Added some code to help
class Class1
{
public int number { get; set; }
public void Counter()
{
for (int i = 0; i < 10; i++)
{
number = i;
System.Threading.Thread.Sleep(5000);
}
}
}
and the form:
Class1 myClass = new Class1();
public Form1()
{
InitializeComponent();
label1.Text = myClass.number.ToString();
}
NO,
I think your form needs to access a reference to Class1 to use the data available in that, and not the other way around.
VERY seldomly a data class should instanciate a display form to display what it has to offer.
If the class is a data access layer of singleton, the form should reference that class, and not the other way around.
Based on the comments in your original post, here are a few ways to do it:
(this code is based on a Winform app in VS2010, there is 1 form, with a Label named "ValueLabel", a textbox named "NewValueTextBox", and a button.
Also, there is a class "MyClass" that represents the class with the changes that you want to publish.
Here is the code for the class. Note that I implement INotifyPropertyChanged and I have an event. You don't have to implement INotifyPropertyChanged, and I have an event that I raise whenever the property changes.
You should be able to run the form, type something into the textbox, click the button, and see the value of the label change.
public class MyClass: System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string AValue
{
get
{
return this._AValue;
}
set
{
if (value != this._AValue)
{
this._AValue = value;
this.OnPropertyChanged("AValue");
}
}
}
private string _AValue;
protected virtual void OnPropertyChanged(string propertyName)
{
if(this.PropertyChanged != null)
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
Example 1: simple databinding between the label and the value:
So this time, we will just bind the label to an instance of your class. We have a textbox and button that you can use to change the value of the property in MyClass. When it changes, the databinding will cause the label to be update automatically:
NOTE: Make sure to hook up Form1_Load as the load event for hte form, and UpdateValueButton_Click as the click handler for the button, or nothing will work!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MyClass TheClass;
private void Form1_Load(object sender, EventArgs e)
{
this.TheClass = new MyClass();
this.ValueLabel.DataBindings.Add("Text", this.TheClass, "AValue");
}
private void UpdateValueButton_Click(object sender, EventArgs e)
{
// simulate a modification to the value of the class
this.TheClass.AValue = this.NewValueTextBox.Text;
}
}
Example 2
Now, lets bind the value of class directly to the textbox. We've commented out the code in the button click hander, and we have bound both the textbox and the label to the object value. Now if you just tab away from the textbox, you will see your changes...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MyClass TheClass;
private void Form1_Load(object sender, EventArgs e)
{
this.TheClass = new MyClass();
// bind the Text property on the label to the AValue property on the object instance.
this.ValueLabel.DataBindings.Add("Text", this.TheClass, "AValue");
// bind the textbox to the same value...
this.NewValueTextBox.DataBindings.Add("Text", this.TheClass, "AValue");
}
private void UpdateValueButton_Click(object sender, EventArgs e)
{
//// simulate a modification to the value of the class
//this.TheClass.AValue = this.NewValueTextBox.Text;
}
Example 3
In this example, we won't use databinding at all. Instead, we will hook the property change event on MyClass and update manually.
Note, in real life, you might have a more specific event than Property changed -- you might have an AValue changed that is only raised when that property changes.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MyClass TheClass;
private void Form1_Load(object sender, EventArgs e)
{
this.TheClass = new MyClass();
this.TheClass.PropertyChanged += this.TheClass_PropertyChanged;
}
void TheClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "AValue")
this.ValueLabel.Text = this.TheClass.AValue;
}
private void UpdateValueButton_Click(object sender, EventArgs e)
{
// simulate a modification to the value of the class
this.TheClass.AValue = this.NewValueTextBox.Text;
}
}
There's no reason why you can't have multiple instances of a form, but in this case you want to pass the Class1 instance to the form you have. The easiest way is to add a property to Form1 and have that update the label text:
public class Form1 : Form
{
public Class1 Data
{
set
{
this.label.Text = value.LabelText;
}
}
}
Events and delegates are what you want to use here. Since you tagged this as beginner, I will leave the implementation as an exercise :), but here is the general idea:
Declare an event/delegate pair in your data class.
Create a method in your form to bind to the event.
When "something" happens in your data class, fire the event
The form's method will be invoked to handle the event and can update widgets appropriately
Good luck.