In c# winforms, I am having a problem whereby this block of code will create two variables that point to the same form instead of two different instances of the form:
Form formA = new LoginForm();
Form formB = formA;
formB.Close();
When formB is closed, both forms are closed. I am trying to avoid this, however I cannot find any solution such as formB = new Form(formA);
In my real solution, there are extra controls added to the first form (formA), and some additional data stored in the fields of the form. This is why I need to duplicate the first form
Any help is much appreciated!
If you want two forms, create two forms - two independent objects - by calling the constructor twice:
Form formA = new LoginForm();
Form formB = new LoginForm();
Now they're independent objects. Note that there's nothing winforms specific about this - it's the same for all classes.
EDIT: If you want to create a clone of the original form, you still need to create a new object - and each of the controls within the form would need to be cloned as well (a control can't have two parents). Cloning is a tricky business to get into, and I'd try to avoid it here if possible. Instead, I would try to effectively replay the same original actions which added the controls or set the data in the original form.
You haven't said much about what information is within your form, but if it's complex data, you probably want to isolate that from the form, encapsulating it in its own class... then you can decide whether you want a deep or shallow clone of that object when you create the second form.
There's not a single statement to do what you're asking.
You can create the second form, then copy the controls from the first to the second form, maybe using Controls.CopyTo (I'm not sure about CopyTo).
To handle the data, you can make a class that contains all the data you need to use, and copy clone of that class to the new form. Then you can manually populate some fields on the new form.
Related
I have a selection of TextBoxes that a user fills in when they wish to note that they have had contact with another person. Most of the TextBoxes are imply filled in by typing into them. However, for one of them I would like the user to be able to select from a list of People that appears when they click on a button.
This is where I am having problems. So far I have just made a DataGrid appear and handled it's SelectionChanged method to fill in the TextBoxes text property. This has worked fine, however now there is not enough space on the current page to show an entire DataGrid with all the people they can select from.
I've decided to show the People in a separate, smaller Window that appears when the user clicks a Button. The issue I have is that when the user selects the Person they wish to mark the contact for in the new Window, I have no idea how I can notify the original Window that a Person has been selected, close the new smaller Window and fill in the appropriate TextBox on the original Window.
What would be the most intuitive way to fill in the TextBox on the original Window, based on the selection on the Window that opens?
I would use delegates,which call a function of the original window and parse the changed variable with it. So you know when the user clicked something and you can directly react to this "event".
Link:
https://msdn.microsoft.com/en-us/library/ms173171.aspx
If you use a framework like Galasoft's MVVM Light (http://www.galasoft.ch/), they have a messenger system just for this purpose. It allows you to "broadcast" messages that can be "received" by any other part of the application
This is when considering using Domain, Model, Presentation (Winforms/WPF version of MVC formatting) to do your app.
You can have each form as its own class, well they are their own class. Create each form class but add some public members to it if the controls are private. Have them have "get" properties only and to return the values of whatever controls or variables are in that form. Your main form will be the controlling form. All forms will be handled by the main form so when you open it, it is a class the main form can access.
Now, if I remember (been doing more MVC and not any Winforms lately) I believe if you use the ShowDialog() method it will freeze the main thread so when you close out the main form you can continue and read in public members you have in your forms class you opened. Synchronous I believe it runs as. If you use just Show() the thread will keep on trucking, asynchronous. With asynchronous you may then have to use a main form in your startup code so there is always a window there but subscribe to the close event of your forms and have a method that can grab those public members out. Be sure to instantiate the extra forms at the root of the main class so it doesn't fall out of scope when it exists the method that calls it. You may even be able to make the method that calls is a async call and have an await before the command that runs the Show method on the form.
Summary, treat each form as its own class but add public members that can read the values from the controls and/or variables you want. Read that data from the class when it closes via an event or synchronously when the thread closes out from the form closing. The form closing doesn't discard the object, just the visualization of the form.
Oh, if you are passing info from the main form to a child for you are opening, either add a constructor for that form class that takes your input as a model or values to fill in the appropriate variables or forms before showing it or create a public property you can put your values you want to send in before showing the class.
Remember, everything is a class, once you look at it as such and treat it as such, the answer will come. :-)
I should warn, I am a long winded explainer.
At work putting all this down from memory so some errors may exist. Let me know if there are.
I think the problem is to access the controls of the main window, isn`t it?
You can define an event of changing user`s choise and access MainWindow control by using the following construction:
((MainWindow)Application.Current.MainWindow).MyTextBox
I have 3 forms. How can I make it so that one form is shown with .Show() and the other is hidden with .Hide() from a separate form?
This is part of my code
private void buttonYes_Click(object sender, EventArgs e)
{
LoggedIn loggedinform = new LoggedIn();
loggedinform.Hide(); // Hides another form that is in the background
MainForm mainform = new MainForm();
mainform.Show(); // Show first form
this.Hide(); // Hides current form
}
One problem, the LoggedIn form does not hide itself. From the looks of it it skips it and just goes for the mainform.Show();
Is this a bug or do I need to do something else?
The line LoggedIn loggedinform = new LoggedIn() is going to create a new instance of that login window. That might be useful if, say, you intended to show 5 "Login" windows onscreen all at once. I think what you want to do is retrieve a reference to the login window that is already showing, and hide that; so, avoid creating a new one.
Properly passing references to existing objects around the program is kind of a structural problem, and one that I ran into quite a bit in my early programming days. The quick, unclean, and generally not-recommended way is to declare instances of those singular objects (like, maybe, your login window) as static, so they can be retrieved anywhere. However, to fully answer your question in the best way, maybe you could describe the structure of your program a bit more (full code isn't necessary, just generally-speaking, what the flow is between classes)
Ok I figured it out. I can use
Application.OpenForms[1].Hide();
[1] is the form I'm trying to hide. And it worked.
I also realized thanks to Katana that it makes sense why it wasn't working because it was basically making a new instance of the form instead of finding the current one. Sorry that my code is a mess.
I am trying to specify the parent MDI form when showing a form in c#
All the examples suggest just using
FormVariable.Parent = this;
this works ok assuming you want the form to be opened from the parent window all the time.
I want to be able to open a form and set the Parent form to my MDI Parent form by specifying the name.
in VB.net I have used
Me.MdiParent = TheNameOfMyParentForm
When I try anything similar in c#
this.MdiParent = CruxMDI();
I get
'Crux.CruxMDI' is a 'type' but is used like a 'variable'
Form.MdiParent has to reference a concrete instance. So, maybe it would be a good idea to implement a Singleton pattern (you probably don't want to allow multiple parent windows either way, do you?) in your Parent container, so that you can reference it from wherever you need to. Then you'll just type:
this.MdiParent = CruxMDI.Instance;
If you want to add such behavior automatically and it needs to happen in many Forms in your application, you may consider an option when you'd create a custom base class inheriting from Form. That way you specify this once and then you just need to be sure to inherit your new Forms from this baseclass instead of a default Form.
Either way, you need to have some kind of mechanism to reference the instance of your MDI container.
i have read this question How to Create Form from within non gui thread C# but it didnt helped me.
I have a List of Tables which has a List of Players and each Player has his own Form (i seperated it in player.cs and playerform.cs)
The Problem is:
if i make the Table inherited from Form (Show the Form and make visible=false, so its not shown) then i can make an Methodinvoker
//table.cs
class Table : Form{
var player = Players.First();
this.Invoke(new MethodInvoker(player.ShowForm));
//player.cs
void ShowForm() {
var form = new PlayerForm();
form.show();
}
this is working, without any problems or sideeffects. but a little nasty, inherit the Class from Form, just to use Invoke. (my table dont need a Form, so i want to fix this)
how can i use invoke, if i dont have a form?
thanks
I would suggest that you not try to create forms on the non-UI thread unless you have a very compelling reason to do so. Doing that creates complexity that can be avoided by using other, more standard approaches.
For example, if you want processing to happen in the background for each form, you can use a BackgroundWorker instance for each separate form.
If you have a long-running process, such as indicated in the question you link to, that process can use an event to request that a form be shown via the standard UI thread.
Still getting used to WPF from a win forms programmer. I have multiple forms in an application that can be accessed from multiple locations, so I need to keep the forms "global" as I'm not sure of a better terminology.
For instance "Details" can be opened from a "Main Menu" but can also be opened from a grid in "Search", I'd like the details returned from the search to be displayed in the "Details" page even if it was pre-opened from the main menu.
I've come across Application.Current.Properties and have started storing a few forms in it but it just feels plain wrong to set:
Vehicle vehicleForm = new Vehicle();
Application.Current.Properties["frmVehicle"] = vehicleForm;
And then to access it:
if (Application.Current.Properties["frmVehicle"] == null)
Application.Current.Properties["frmVehicle"] = new frmVehicle();
Vehicle vehicleFrm = (Vehicle)Application.Current.Properties["frmVehicle"];
vehicleFrm.Show();
vehicleFrm.Activate();
I have just discovered Application.Current.Windows as well which has thrown me a little.
What is the most efficient/industry standard way of dealing with form like this?
I would just check whether Application.Current.Windows contains an instance of your window. If so then you give it focus, if not then you create an instance.
I'm not sure if I understand how are you opening the window correctly. But if all you want to do is to have one instance of the window through the whole run time of the application, you can use the Singleton pattern. Basically, the window class has a static property that holds the only instance.
If you don't need to keep any state in the window, you can just create new instance of it every time you want to show it.