Call a usercontrol’s method from a form c#? - c#

I have the method listviewupdate() in usercontrol schuler.
Usercontrol schuler is in form1.
Then I have form2. When I click a button in form2 I want to call the method listviewupdate().
I tried creating a second method in form1 which calls the listviewupdate() method, and then calling this second method in form 2 but I get an error.
Can somebody please help me?

In your file Program.cs, you can define a globally accessible variable:
static class Program
{
// for external access to Form1 methods
public static Form1 MainForm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new Form1(args);
Application.Run(MainForm);
}
}
The static variable MainForm can then be used to access any public method to Form1 via Program.MainForm.MyMethod().
Assuming, you have access to the Form2 object from within Form1, you can use the Form2 object variable to call Form2 methods out of Form1 methods.
Be aware that you might run into problems when (unknowingly ...) using more than one thread. Read about BeginInvoke.

#Axel Kemper thanks for the response. I did how you told me with Program.MainForm.MyMethod() but it didn't find MyMethod().
Then I went in the form1.Designer and there I saw that the usercontrol was set to private, also I switched it to public and now it works with Program.MainForm.schuler1.MyMethod() //schuler1 is the name of my user control.
I just don't understand why it doesn't work with
Form1 form1 = Application.OpenForms[1] as Form1;
form1.schuler1.ListviewUpdate(); //schuler1 is the name of my usercontrol
even if the user control is set to public I get the error "System.NullReferenceException" in main.schuler1.ListviewUpdate();

Related

How to close form and open another

Currently learning to code in C#. I have used the code
Form1.Hide();
Music_Menu.Show();
The names for the forms are correct and believe this should work but I get this error when I hover over the text:
an object reference is required to access non static field member or
property c#
I am betting that Music_Menu is the name of your form's class.
You need to create an INSTANCE of the form. VB did this "behind the scenes," but C# demands you get it right.
Somewhere in Program.Main(), I'll bet you have a line:
Application.Run(new Form1());
You need to keep that reference. A private static field in the Program class should work.
private static Form1 _myForm1;
private static Music_Menu _myMusic_Menu;
Then in the Main() method, change that to:
_myForm1 = new Form1();
Application.Run(_myForm1);
Then your code (where you switch) should be (in Program.cs):
_myForm1.Hide();
_myMusic_Menu = new Music_Menu();
_myMusic_Menu.Show();
Alternatively, if you want to run the code in Form1 (and assuming you want to come back to your instance of Form1:
this.Hide();
var myMusic_Menu = new Music_Menu();
myMusic.ShowDialog();
this.Show();
You'll probably have some scope issues to straighten out depending on your context, but this should get you going in the right direction.

How do I communicate with a control of a Form from another class?

A little new to C#, and approaching something beyond me. Apologies for length.
I have a Windows Form application in Visual Studio C# Express, using the default classes VS spawns. I want to start and stop a Marquee style progressBar from a class other than the default Form1 in which it is declared.
These seems surprisingly difficult, I am sure I am missing something important.
My project has the usual classes that Visual Studio auto generates:
Form1.cs, Form1.Designer.cs , Program.cs .
I added myClass.cs that wants to talk the load bar.
I add progressBar1 bar to my form using the designer, setting Style:Marquee.
In Form1.cs' Form() constructor, I write
this.progressBar1.Visible = false;
This works. Intellisense 'sees' progresBar1.
code in Form1.cs can see and control progressBar1 declared in Form1.Designer.cs.
this makes sense to me.
But the functions which need to start and stop the load bar must live in myClass.cs.
I want to be able to code like this, within myClass.cs:
public void myFunction(){
Form1.progressBar1.visible=true
//do stuff that takes a bit of time
Form1.progressBar1.visible=false
}
This does not work. Intellisense cannot 'see' progresBar1 when typing code in myClass.cs.
In fact, intellisense cannot 'see' anything in Form1.cs from within myClass.cs.
No public propeties or functions added to Form1 ever become visible to intellisense.
This does not make sense to me, I am confused.
This seems like something you would want to do often and easily.
Some searching indicates that this blocking of external access to Form controls is by design. Something to do with 'decoupling' your logic code from GUI code, which makes sense in principal.So clearly there is an expected approach, yet an clear example is hard to find. I can only find examples of loadbars controlled from entirely within the Forms that declare them, or terse half-examples about creating and registering Events or using Invoke or other things I know too little about. There are many apparent solutions but none that I can see clearly apply to me, or that I am able to implement, in my ignorance.
I think I could do it if my Form were an instance.
[EDIT] nope. instance or not, Form1 controls never become exposed outside of Form1.cs
So, How do I to start and stop a Marquee style progressBar from a class other than the default Form1 in which it is declared, in the proper way?
Is there a clear and useful example somewhere?
You can't access your properties this way:
Form1.progressBar1
because Form1 is a type (not an instantiated object). The only methods or properties you can access with this approach have to be marked as static.
To answer your question of how to communicate, you probably want to use the event approach that you mentioned. First you need an event in your logic class:
public event Action<int> UpdateProgress;
Which is called just like a function:
if (UpdateProgress != null)
UpdateProgress(10);
This declares a new event using the Action generic delegate, which means the listening function has to return void and take one int as a parameter.
Then in your forms code, you'll have:
MyClass logic = new MyClass();
private void SomeFunction
{
logic.UpdateProgress += UpdateProgressBar;
}
private void UpdateProgressBar(int newProgress)
{
progressBar1.BeginInvoke(new Action(() =>
{
progressBar1.Value = newProgress;
}));
}
This creates a new instance of your logic class, and assigns the function "UpdateProgressBar" to be called whenever your logic class raises the UpdateProgressBar event. The function itself uses Dispatcher.BeginInvoke because your logic class is likely not running on the UI thread, and you can only do UI tasks from that thread.
There is a lot going on here, so please let me know if I can clarify anything for you!
I would create a model that has properties matching your form, and pass that around.
So you would make a new class like this...
using Windows.Forms;
public class Form1Model {
public ProgressBar progressBar { get; set; }
}
Then when you want to get to your other class holding that function you would create an instance of Form1Model, fill it, and call your function
var fm = new Form1Model {
progressBar = this.progressBar1;
};
otherClass.MyFunction(fm);
now you would have to change your function to accept the new model
public void MyFunction(Form1Model fm){
// do stuff
}
Another option is just making the function take an instance of the form, and not creating a model, but then you are going to be passing a lot of extra bits you probably won't care about
public void MyFunction(Form1 form){
// do stuff
}
Then on your form you would call the function like this
otherClass.myFunction(this);
I would recommend the first way over the second, you can control what data is being passed around
You are trying to access the type Form1 instead of the forms instance. I'll show you, how you can access the instance below.
I assume that Form1 is the applications main form that stays open as long as the application runs. When you create a WinForms application VS creates this code in Program.cs:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
A simple way to make your main form accessible throughout the application is to make it accessible via a public static property. Change the code like this
static class Program
{
public static Form1 MainForm { get; private set; }
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new Form1();
Application.Run(MainForm);
}
}
In Form1 create a property that exposes the progress bar's visibility:
public bool IsProgressBarVisible
{
get { return this.progressBar1.Visible; }
set { this.progressBar1.Visible = value; }
}
Now you can make the progress bar visible from any part of the program like this:
Program.MainForm.IsProgressBarVisible = true;
Another way of accessing the main form is, since it is always opened as the first form:
((Form1)Application.OpenForms(0)).IsProgressBarVisible = true;
However, it requires the form to be casted to the right type, since OpenForms returns a Form.
And don't forget: A Form is just a class like any other class. You can do almost everything you can make with other classes. So, communicating with forms is not very different than communication with other objects, as long as you are not using multithreading.

How to detect whether a Form is a Instance or Form itself

This is somewhat different question or maybe a easy question. but I have this problem now.
I have three forms loginForm, mainForm and subForm.
In my loginForm I have two accounts, one for mainForm access and other for subForm access. The mainFormAccessAccount can access both mainForm and subForm but the subFormAccessAccount can only access subForm. Through mainForm we can create multiple instances of subForm (mainForm is single instance).
Now my problem is: I want to implement different subForm_Closed Event functions for a subForm and its Instances (instances created by mainForm).
I used the below code to create the instances of subForm in subForm.cs
private mainForm MainForm;
internal void RegisterParent(mainForm form)
{
this.MainForm = form;
}
and in mainForm.cs to create instance of subForm, I used the below code:
subForm newSubForm = new subForm();
newSubForm.Show();
newSubForm.RegisterParent(this);
How can I solve this issue?
(I am not sure whether they are called instances or not because I am a Dot net noob)
Thanks in Advance.
If I understand your problem correctly you want two different handlers for close event of the SubForm.
One handler for close events of the SubForm created through subFormAccessAccount
Another handler for close events of the SubForm created through MainForm
As you suspected, this is indeed an easy problem and since you mentioned you are a .net noob I will try to explain in detail.
If I am not wrong you generated the event handler subForm_Closed using Visual studio designer surface. This seems to be the cause of your confusion.
What does the Visual Studio Designer do to generate event handler:
If you open SubForm.cs notice the definition of its constructor. It will be something like this
public SubForm()
{
InitializeComponent();
//May be some other code as well
}
This InitializeComponent method is described in SubForm.designer.cs file () (expand SubForm.cs in solution explorer and you will be able to see it).
One of the lines in InitializeComponent method will be something like this
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SubForm_Closed);
So in effect as soon as you create a SubForm 'instance' (here I mean real object instance and not in the sense you mentioned in your question which is at best a child form) either through subFormAccessAccount or through MainForm, it attached your SubForm_Closed event handler to the FormClosed event.
How can you get the desired behavior?
If you want to handle the closed event in SubForm.cs, you can do something like this
internal void RegisterParent(mainForm form)
{
this.MainForm = form;
this.FormClosed -= SubForm_Closed; //Unhook previous handler
this.FormClosed += SubFormAsChild_Closed; //hook new handler
}
If you want to handle the closed event in MainForm.cs, you can do like this
internal void RegisterParent(mainForm form)
{
this.MainForm = form;
this.FormClosed -= SubForm_Closed;
}
//in MainForm.cs
newSubForm.RegisterParent(this);
newSubForm.FormClosed += newSubForm_Closed;
Several ways to go
Add another constructor to SubForm
e.g.
public SubForm(Boolean argCreatedByMainForm) : this()
{
// save argument in private member variable for use in OnCloseQuery
}
then use
subForm newSubForm = new subForm(true);
newSubForm.Show();
newSubForm.RegisterParent(this);
It's not the way I'd go, because having one form know about another, tends to turn into a maintenance nightmare, but you'd need some more tools in your programming box to implement better solutions. A class to manage the interraction between forms for instance, then abstract them out to interfaces, last but not least inject the behaviour.
Seeing as you are learning, get constructor working, the you can progress to stupidly clever as you pick up the techniques
subForm newSubForm = new subForm();
newSubForm.Show();
newSubForm.RegisterParent(this);
newSubForm.Close += (s, e) =>
{
// Close event will be fired for this instance only.
};
I would recommend to have an other structure of you mainform - subform referencing.
Your Subform is dervived from System.Windows.Forms.Form, which is derived from System.Windows.Forms.Control, which actualy has already one property to store a parent control:
So you should store there the reference to the main form.
The other thing is that you should implement a static method to create subforms in your mainform, which acutaly calls a private methods of the single instance reference to create the real subform - i asume that you you the singleton pattern.
so code would look like this
public class MainForm : System.Windows.Forms.Form
{
// used to hold references to subforms note: not static
private List<SubForm> mySubForms;
// singelton implementation
private static MainForm theInstance = null;
private MainForm()
{
mySubForms = new List<SubForm>();
}
public static MainForm GET_INSTANCE()
{
if (MainForm.theInstance == null)
{
MainForm.theInstance = new MainForm();
}
return MainForm.theInstance;
}
// creates subforms and the references right not:static method as singelton
//pattern is used
public static SubForm CREATE_SUBFORM()
{
SubForm newSub = new SubForm();
newSub.Parent = theInstance;
theInstance.mySubForms.Add(newSub);
return newSub;
}
}
Please aplogize if the code has some typing errors ... i dont have an IDE right now. Obiously I didnt implement the singelton pattern threadsafe...this would be corss the edge for demonstraion purpose.
Edit:
An even better practise would be to let forms comunicate by making use of evetns. This would be the best way if you plan to have a multithreaded application. But you need advanced .Net skills to it this - imo.

How to exit a Windows Forms/C# program

Class A has a Form1 (subclass of System.Windows.Forms.Form) member.
class A {
Form1 form;
public A()
{
form = new Form1();
form.Show();
}
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
A a = new A();
Application.Run();
}
The problem is I do not know how to exit the program. I have tried Application.Exit() when handling the Form.Closed event or call A.Dispose(), but the Windows Task Manager still lists the process of my program.
How do I finish this program?
Application.Run has 3 overloads. You are using this one with no arguments.
Windows runs your program in a message loop, but it doesn't care about your form.
So if you close your form it doesn't matter; the program will still run.
The second overload is what everyone uses, Application.Run(Form). This one runs a Windows message loop over your form, so when you click close on the window, the application closes.
Your code should be:
class A {
Form1 form;
public A()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new Form1();
form.Show();
Application.Run(form);
}
}
[STAThread]
static void Main()
{
A a = new A();
}
Following Microsoft you should use this:
Application.Run(a.Form);
Because MSDN states that
Most Windows Forms developers will not need to use this version of the method. You should use the Run(Form) overload to start an application with a main form, so that the application terminates when the main form is closed.
I think you have a mixup there. Check the documentation for Application.Exit.
There you will see that Exit will raise the Closed event for you, and calling Exit there might cause an infinite loop (which might be causing your problem, that the application is still visible).
Try this:
Environment.Exit(1);

What is the entering method of a multi form project?

I'm working with a C# project using System.Windows.Form to create the GUI, I have two forms within the VS project( MainForm and InitialPrompt). I've never used Forms before and Google hasn't been of much help.
Intended action:
InitialPrompt Load
Click Button on InitialPrompt
Load MainForm
However, since MainForm was created first there is some property/method that allows it to load first and the InitialPrompt does not load at all. How to I make MainForm the secondary form and InitialPrompt the primary?
Thanks in advance.
namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
You can change the above code to read
Application.Run(new Form2()); // or whatever the name of the second form is.
This is found in your Program.cs file.
Look for the Program.cs file inside your project. Inside you will see something like this:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
Just change new MainForm() to new InitialPrompt(). This will make InitialPrompt the main form.
Like any other .Net project it is the static void Main() method in a class defined in your project. Because of this, only one static void Main() method is allowed in a project.
NOTE: this static Main method must be defined as void return type, and it can either take no arguments, or it can be defined to take an array of strings to be passed as command line arguments.

Categories

Resources