How to close form and open another - c#

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.

Related

Issue with referencing Winform form

I have bean having a issue referencing a winform form I initialize in main, the code for the referencing is as follows,
Form1 f1 = new Form1();
Application.Run(f1);
f1.changeText("Hello World");
the form itself is defined in another file. f1.changetext is a simple function which takes a string input and sets a text block element to the string, I call the function in the form class as the result of clicking a button and that works fine but when I call it in main I get no result. As a side note I have a console.writeline function in main as well that doesn't do anything but I don't know if that's related. For context I'm using Visual studio and if it wasn't obvious I don't have too much experience with coding with classes and frameworks like this. Thanks for any assistance!
I'm not familiar with Application.Run(f1); also shouldnt you change the text prior to "Running it?"
It Being:
Form1 f1 = new Form1();
f1.changeText("Hello World");
Application.Run(f1);
A way I'm sure will work (the one I use) with showing / initializing another form would be
Form1 f1 = new Form1();
f1.changeText("Hello World");
f1.ShowDialog();
Have you tried Debug to check if the code works / was read when running?
Welcome to StackOverFlow!

Running an exe converted to a dll from another exe

I have a completely functioning application that I have converted to a Dll.
I need to be able to run that application (now dll) out of an exe . Ive added the dll as a reference to the new exe and have tried to just instantiate a frmMain object from the namespace used in the dll and show it like I would in any other application.
However, I get a bunch of null reference exceptions in several of the references that I had in the exe that I converted to a dll.
I've also tried the solution here Launch Dll using C# program
and tried jumping to the Program.cs Main() function at which point I get a "SetCompatibleTextRenderingDefault must be called before the first IWin32Window object is created in the application." error.
Here is the dll's program.cs
namespace VTRS
{
class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new frmMain());
}
//had to add this because exe can't find Main
public void invokeMain()
{
Main();
}
//you have to have a constructor for the exe to instantiate this class
public Program()
{
}
}
}
and here is the new applications code
private void button1_Click(object sender, EventArgs e)
{
try
{
System.Reflection.Assembly dll1 = System.Reflection.Assembly.LoadFile(Application.StartupPath + "\\VTRSTCACodeMaintenance.dll");
if (dll1 != null)
{
object obj = dll1.CreateInstance("VTRS.Program");
if (obj != null)
{
System.Reflection.MethodInfo mi = obj.GetType().GetMethod("invokeMain");
mi.Invoke(obj, new object[0]);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Can anyone explain to me why this doesn't work or point me in the right direction? I'm super confused and am not doing this by choice (I'm being told to by the boss)
You do not need reflection, nor do you need to execute the Main() method of your original .exe file (indeed, you should probably just remove it, if that project is intended to just be a plain DLL).
You don't need reflection because, once you've added the assembly as a reference in your new project, all of the public types and members are accessibly in your new project. Just make sure you've declared frmMain as public (this is the default in Visual Studio, so it may already be public). Then instead of all that reflection rigmarole, all you need to do is what you'd normally do to show a form:
frmMain form = new frmMain();
form.Show();
or even just:
new frmMain().Show();
You don't need to execute the Main() method, because all it does is work that your new project already does:
The [STAThread] sets the entry point thread (which becomes the main UI thread) to the STA apartment model. But since your new project is also (it seems) a Winforms program, you already have an entry point and a main UI thread that has been correctly configured. It's this thread in which the Click event for button1 is raised, and so you are executing in that thread when the button1_Click() method is called.
Likewise, the calls to set the visual styles and text rendering. You don't need to call these again, because your new project called them when it started.
Finally, the call to Application.Run(new frmMain()). This call has three effects: it creates an instance of frmMain() (which you can do yourself as I noted above), it then passes that instance to the Application.Run() method so that method can call the Show() method on the form (again, you can do that yourself), and then the Run() method sits in a loop dispatching window messages. You also don't need to do that because, again, you are already in a Winforms program, which has already called Application.Run(), and is already dispatching window messages (which is how the Click event got raised in the first place).
So, stop trying to invoke the Main() method, just make sure the form class you want to use is public so it's visible from projects that reference the assembly, and just create and show the frmMain object the way you would if it were declared in the same project.
I think it's because of the access modifier of the class program just change it to public.
also if you don't load a changeable dll (dynamic) why you don't just reference it to the project as you would normally do with other dll's and call the main from the program class (you still need program class to be public)
In Solution Explorer, in your project view right click on References --> Add New Reference --> Browse --> Find VTRSTCACodeMaintenance.dll(it should be in your \bin\debug folder) --> double click it --> click Ok.
That is basically.

MS Visual Studio C# - Can someone explain to me why my code isn't working and how I can get it to work?

I'm writing a program to conduct a search within Windows Active Directory and return the search results to another form in a listbox.
This is what my getter method looks like on the main form:
public List<String> getSearchResults()
{
List<String> accountList = new List<String>();
foreach (SearchResult account in searchResultCollection)
{
accountList.Add(account.Properties["cn"][0].ToString());
}
return accountList;
}
It is called only on the second form at load:
private void AccSelect_Form_Load(object sender, EventArgs e)
{
List<String> accountList = Main_Form.getSearchResults();
}
However, the compiler tells me that "An object reference is required for a non-static method". But my getter method cannot be static at all.
From my research prior to asking this, it seemed like I would need an instance of the class that owns my getter method (so my main form) to be running. Which is fine since my first form is what instantiates the second form. The second form will never be running without the first form anyway.
Can anyone give me a possible solution to this? :C
when you need to call a method in the main form from the child form, can code like this (assumes your main form is of type MainForm):
MainForm parent = (MainForm)this.Owner;
parent.getSearchResult();//CustomMethodName();

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.

Categories

Resources