What am I missing?
Method in form1.cs:
public partial class Form1 : Form
{
...
public void DoSomething()
{
<Database call to update a list on Form1>
}
...
}
From a User Control:
public partial class UserControl1 : UserControl
{
...
private void UserControl1_Load(object sender, EventArgs e)
{
Form1.DoSomething();
}
...
}
I am unable to access the method. I tried using "Form1 frm = new Form1()" and
when i attempt to use frm.DoSomthing() it exist but doesnt actually update the
list, i know the update code works and I know there is data becaue i tested. I
think my problem with this is that the "NEW" keyword is making a different
object and not updating the original object.
The UserControl shouldn't be able to access methods on Form1. What you may want to do is have an event that fires on your UserControl that Form1 is listening to and updates the list. Without knowing more of your architecture and what is actually going on it's difficult to give you more specific advise.
Related
newbie question :(
I'm making a program using windows forms and i have a lot of small methods like this
private void label1_Click(object sender, EventArgs e)
{
textBox1.Select();
}
private void label13_Click(object sender, EventArgs e)
{
textBox13.Select();
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
plotGraph(prostokat);
}
in the Form1.cs file and to make the code more transparent, I would like to move these small methods out somewhere to an external file (class?) but I don't really know how to do this. If they were normal methods I would just make a class and create an object of that class and just call the methods using that object but these are functions that "happen" when a user action is performed i.e. a textbox is clicked, so I'm not sure how to make this work.
It is possible to create an extra partial class (separated file) for your Form1 and place your cluttering methods there.
Or you could collapse them with #region
#region UI Handlers
#endregion
The perfect solution would be using some kind of MVVM for WinForms. In that case in your ViewModel you can implement your business logic separately from the code-behind.
Check out this:
https://www.codeproject.com/articles/364485/mvvm-model-view-viewmodel-patte
Hope it helps!
Have a look at your Form class subsection. It most cases it is still a partial class. Create a new .cs file in the same subsection in your project and add another partial form class to it.
You can find additional information here:
Partial Classes and Methods
Sure, you can add a new class to your project (right-click the project in Solution Explorer --> Add Class --> ) and put your methods there. Then you will need to hook the methods up to the controls in code:
I added a static class called "Form Methods" and put a method in there for label1 Click event:
static class FormMethods
{
public static void label1_Click(object sender, EventArgs e)
{
Label label = (Label) sender;
// Try to find the textbox through the label's parent form
TextBox textBox = (TextBox) label.Parent.Controls.Find("textBox1", true).First();
if (textBox != null)
{
textBox.Select();
}
}
}
Then in the Form Designer code, you can hook up the event:
this.label1.Click += new System.EventHandler(FormMethods.label1_Click);
Alternatively, you can make the class part of your original form class, and it will still be a separate file. If you want to do this, you can then make your event a private non-static method, and you would change the class definition to a public partial class:
public partial class Form1 // <-- This used to be: static class FormMethods
{
// This used to be: public static void label1_Click
private void label1_Click(object sender, EventArgs e)
{
. . .
And then hooking up the event looks like:
this.label1.Click += new System.EventHandler(label1_Click);
You can create any number of partial class files mimicking your original and group methods inside as your functionally needs - however, you won't be able to use the designer to directly navigate to your callbacks. That is, if you double click a graphic element or click an event of a graphic element you will have an unexpected behavior: in both cases you will have an event handler generated in your first partial and a hook created to that . . . so you can't directly navigate to those handlers anymore, and you need to go trough your partial files looking for their definitions.
Use partial to split C# code like this.
public partial class Employee
{
public void DoWork()
{
}
}
public partial class Employee
{
public void GoToLunch()
{
}
}
Im having a strange problem with my programme, whenever I call a method from another class, it doesnt work as expected. Basically, what I am trying to do is add an item to a listview, and the code is in a method, and I am trying to invoke that method from another class. Here is my code:
public class Main1
{
public void addItemToLV(string text)
{
listView1.Items.Add(text);
}
}
public class MainForm
{
Main1 m1 = new Main1();
m1.addItemToLV("test");
}
Any ideas why this is happening? Thanks.
Under normal circumstances, the controls on a form are declared as protected properties within the designer.cs file rather than public properties, so those controls will normally not be accessible to code outside of the form on which they are declared. This is intentional, as it encourages good object-oriented programming habits.
Rather than modifying a control directly from code that exists outside the form, a better practice is to declare public methods and properties within your form that can be called from outside code to manipulate the protected controls:
public class Main1
{
public static void Main()
{
var mainForm = new MainForm();
mainForm.AddItemToListView("test");
}
}
public class MainForm
{
public void AddItemToListView(string text)
{
listView1.Items.Add(text);
}
}
You could try to pass the ListView as an argument in the constructor and make the function return this ListView to your MainWindow.
public class Main1
{
private readonly ListView _lv;
public Main1(ListView listview)
{
_lv = listview;
}
public ListView addItemToLV(string text)
{
_lv.Items.Add(text);
return _lv;
}
}
I think your code sample is not enough but I am trying to guess the reason behind the issue and I think it is one of the following:
1.You are initialising your listView1 in the load event of Main1, and you are trying to show the form after calling the method. In that case you should call the method after showing the Main1 form.
2. Or simply you are trying to call the method on a different instance than the one displayed.
Why does my attempt at this fail?
I made this public on Form1.Designer.cs
public System.Windows.Forms.ProgressBar progressBar1;
and I can check it shares Form
public partial class Form3 : Form
and then tried this to update increment on another form "form3"
Form1.progressBar1.Increment(10);
I made this somewhat weird try because I saw simple "classname.variablename" for using data from another form working...
PS. If I am lucky enough to understand your generous answers... I think I will be able to bite off more of your further suggestions like "how about try inheritance" or "make instance for this"... :)
The problem with your attempt is that you are trying to access an instance member through the class name, rather than an actual instance reference.
When you create the Form3 instance, you need to pass it the reference to the Form1 instance, preferably via the constructor. E.g.:
partial class Form3 : Form
{
private readonly Form1 _form1;
public Form3(Form1 form1)
{
_form1 = form1;
}
}
Then you can access the ProgressBar instance like this:
_form1.progressBar1.Increment(10);
Note, however, that making the progressBar1 field public really isn't the right thing to do. It gives callers more access than they need, when your classes should be designed to give only the minimum access required.
It would be better to keep the field private and do something like this:
partial class Form1 : Form
{
public void IncrementProgress(int i)
{
progressBar1.Increment(i);
}
}
Then you'd access it like this :
_form1.IncrementProgress(10);
(still passing the Form1 instance to the constructor of Form3, of course).
Edit:
It's worth mentioning that I agree with the general sentiment expressed in the question comments that a better approach is for Form3 to expose some kind of progress event, and for Form1 to subscribe to that, rather than requiring Form3 to specifically know about the Form1 class at all.
The above code examples address the specific question, but if you are interested in a better design, it would look something like this:
partial class Form3 : Form
{
public event EventHandler IncrementProgress;
void SomeMethodWhereProgressHappens()
{
// ... make some progress
// Then raise the progress event
EventHandler handler = IncrementProgress;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
// ... then make some more progress, etc.
}
}
and in your Form1 class:
partial class Form1 : Form
{
void SomeMethodThatShowsForm3()
{
Form3 form3 = new Form3();
form3.IncrementProgress += (sender, e) => progressBar1.Increment(10);
form3.Show();
}
}
Note that in this approach, the Form3 class doesn't have any code at all that depends on the Form3 class specifically, and Form1 does not need to expose the ProgressBar instance in any way, not even via some proxy method.
Finally note that the reason an event is appropriate in this scenario is because of the callback nature of the operation. There are other scenarios where some caller, e.g. the code instantiating the class object itself, simply wants to set certain properties that map to control properties. In this case, the delegation/proxy approach I showed as the initial solution is still appropriate. It's a good technique to learn and use when it applies.
You need to create a public property on Form1:
public ProgressBar MyProgressBar
{
get
{
return progressBar1;
}
}
Then you can access it from Form3:
form1.MyProgressBar.Increment(10);
You'll probably need to create a property in Form3 also:
public Form MainForm
{
get; set;
}
So when you open Form3, you'll do this:
Form3 form3 = new Form3();
form3.Show();
form3.MainForm = this;
I have my form1(Design) with a button in it, but in my form1(Class) it's getting pretty crowded so I want to make a new class. But how do I make the button work in the new class(the new classes name is form2(Class). Of course the function works for the button in form1(Class) so how do I make it work from form2(Class)?
Create your own custom UserControl with own Controls and logic. Or create partial class for your From1 and put events logic there.
It would be worth considering separating your UI code (e.g. button event handling) from the core logic of your application.
There are many way of doing this but the common place to start is with a model class that represents the data and/or logic your window is manipulating.
Try searching on "Windows forms mvc" or "windows forms mvp".
MVP : http://msdn.microsoft.com/en-us/magazine/cc188690.aspx
MVC : Implementing MVC with Windows Forms
What you should really do is use the Model/View/Controller or Model/View/Presenter pattern.
Essentially what you do is to make the Form class (which is the View class) pretty dumb. It doesn't know what to do when various events (such as button presses) occur. Instead, it raises events to indicate what has happened.
Then you write a Controller class which is responsible for creating the View and attaching to its events. The Controller knows what to do when a button is pressed, and responds accordingly (perhaps by calling methods or setting properties in the View class).
The Model is just an abstraction of the data used by the Controller to populate the View class.
Ideally, the View knows nothing about the Model. The Controller is the entity that is responsible for sitting between the Model and the View.
This approach lets you split the business logic out from the form, which simplifies things and makes it much easier to change things and also to unit test.
I posted an example about this a while ago here: https://stackoverflow.com/a/15605436/106159
You should try to disentangle the UI logic from the "business logic", moving it out of the event and in a new class.
e.g. if now you have:
// in Form1.cs
private void btn_Click(object sender, System.EventArgs e) {
OpenDatabaseConnection();
string customerName=SearchCustomerByCode(someTextBox.Text);
someOtherTextBox.Text=customerName;
CloseDatabaseConnection();
}
you should have something like this instead:
// in Form1.cs
private void btn_Click(object sender, System.EventArgs e)
{
string customerCode=someTextBox.Text;
var cs = new CustomerRepository();
string customerName=cs.SearchCustomerByCode(customerCode);
someOtherTextBox.Text=customerName;
}
// in CustomerRepository.cs
//... logic to get the data from the DB, no specific knowledge of form1
public class CustomerRepository.cs
{
public string SearchCustomerByCode(string customerCode)
{
//...
}
}
You could do something like this, which would work, but not very well.
Form 1
public partial class Form1 : Form
{
Form2 f2 = new Form2();
public Form1()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Test");
f2.ShowDialog();
}
}
Form 2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Form1 f1 = new Form1();
f1.button1_Click(null, null);
}
}
I'm trying to write my first program in C# without the use of a tutorial. To ensure that I adopt from the start good coding practices, I want to create each class in an different .cs file. However, I'm running into some troubles when trying to access the elements of the program in such an .cs file.
For example, I have an Form1.cs with an Label and a Start button. When clicking on the start button, a text should appear in the Label. So:
In Form1.cs I have:
namespace TestProgram
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void startButton_Click(object sender, EventArgs e)
{
WriteToLabel message = new WriteToLabel();
message.WelcomeMessage();
}
}
}
And in my separate WriteToLabel.cs file:
namespace TestProgram
{
public class WriteToLabel
{
public void WelcomeMessage()
{
Form1 myForm = new Form1();
//myForm.. --> myForm doesn't have an 'outputLabel'?
outputLabel.Text = "Welcome!"; // This returns an error: 'The name outputLabel does not exits in the current context'.
}
}
}
'outputLabel' is the (Name) I've given the label, and this is in accordance to the name in Form1.Designer.cs.
Both files are using the same components such as 'using System';.
However, from my WriteToLabel.cs file I can't seem to access the Form which holds my program. I did manage to succeed to create different .cs files in an Console Application, which only added to my confusion. So, I have two questions:
First, how can I access the Form from a separate class (i.e. not an partial class) in a separate file?
Second, is this the good way to do it, or is it inefficient to create multiple instances of different classes?
Any thoughts or ideas are highly welcome,
Regards,
The designer automatically creates controls as private fields, because of that your WriteToLabel class can't access it. You need to change that.
Also a good start would be to change the class to something like that:
namespace TestProgram
{
public class WriteToLabel
{
Form1 form;
public WriteToLabel(Form1 form)
{
this.form = form;
}
public void WelcomeMessage()
{
//Form1 myForm = new Form1();
//myForm.. --> myForm doesn't have an 'outputLabel'?
form.outputLabel.Text = "Welcome!";
}
}
}
You're actually instantiating a new instance of Form1, whereas you need to pass in a reference to your existing instance:
public void WelcomeMessage(Form1 form)
{
form.outputLabel.Text = "Welcome";
}
You also need to ensure that outputLabel is a public (or internal) property/field of Form1 so you can set the value accordingly. Then the calling code is slightly different:
private void startButton_Click(object sender, EventArgs e)
{
WriteToLabel message = new WriteToLabel();
message.WelcomeMessage(this);
}
You need to make sure that Form1.outputLabel has public or internal visibility.
You only need something like a LabelWriter class if the class is going to share a significant amount of state or private methods. If all you have is a bunch of methods that set properties on separate objects, you might as well just keep it as a method on the same object (in this case the Form1 object):
void startButton_Click(object sender, EventArgs e)
{
displayWelcomeMessage();
}
void displayWelcomeMessage()
{
this.outputLabel = "Welcome!";
}