The idea is that I would have a set of forms, users would click through a "forward" and "back" button, and the current form would change to a different one. My issue is that I can write code that just pops up a new form, but im not sure how to do a "replacement" of my current form. How is this usually done?
What I did recently was to create a form with buttons already in place and a large panel to contain each step. The dialog would accept an initial step in the form of a IWizStep instance, and the things would roll from there.
Each step was a class exposing a UserControl responsible for the visual aspect of the step, while the logic itself was handled by the class (it was a little more complicated that that, but that was the general idea).
The IWizStep interface, implemented by the step and accepted by the dialog, was on the lines of:
Interface IWizStep
Event StateChanged As EventHandler
ReadOnly Property Control As Control
ReadOnly Property Title As String
ReadOnly Property CanMovePrevious As Boolean
ReadOnly Property CanMoveNext As Boolean
Function MovePrevious As IWizStep
Function MoveNext As IWizStep
End Interface
To put everything together, a controller class would know how to compose the steps necessary for each given action. Therefore I had a controller for, say, "Emit Order", which needed some 10 steps, and a controller for "Emit Orders in Batch", which needed only a couple of steps.
Create a set of UserControls, and add and remove them from a Panel in a single form. (and set Dock to Fill)
You could define a user control which acts as a "wizard". It just needs the buttons you have and an array of content panels, just have it switch through the panels when the buttons are pressed assuming a certain condition is met within the controls on the panel. There's no real definitive "wizard" maker, since it's pretty easy to roll your own wizard.
You don't need to do a "replacement" of your current form really, you could just add a new one to the project. If you do need to for whatever reason, just grab the control collection with Me.Controls, copy that somewhere, and put the new controls up. When you don't need the wizard, swap them out again. It's generally best practice to make a new form however!
Related
For an app that uses user controls instead of forms and the first user control has a listview, where the user clicks or selects "Create New" Or Delete, what is the best way to transfer the data selected in the listview to the detail screen (separate User Control) where the data can be edited?
Can I just reference the list view in the first UC in the Details UC? something like:
ucHeader.lvSetups.FocusedItem.SubItems.Count = 0
from the ucDetail user control?
Saying which way is the best would produce a heated discussion with every ones opinion. However, here are a few ways I would tackle this. While there are more options, these are what I would do:
You should expose any information you want to read from a user control in the form of a property, readonly if you must. Just an example because I don't know what your object types are:
Public ReadOnly Property SelectedItem as object
get
Return Listview1.SelectedValue
end get
End Property
You can also use events to tell the parent of your user control that a selection was made. You can pass whatever you want in this event, even the selected object. If you don't want to pass the selected object, grab it from the property you created (like #1) in the event handler.
I have my form with a menu bar and space underneath to display my controls. One of the buttons in my menu bar is suppose to be a print button that prints a graph that's currently in a User Control I display in the form. If the graph was on the form in the print button's eventhandler I could just simply call
graph.printing.print(true)
which isn't going to work in my case since the graph is in the control and not the form.
How do I communicate with a User Control from the containing form and access or pass its variables when needed? I also have a status bar on the bottom of the form which would also need to get updated from the User Control, but I'll be able to deal with that if I got help with just this one part. Please bear in mind, I also have another User Control I'm going to add to the form which will also contain a graph which will need the same treatment as the other graph on the first control when the print button is pressed. I plan on swapping these two out so I have one form displaying one control at a time.
I got this idea from this answer: https://stackoverflow.com/a/18191630/2567273 but after further research I can't find anyone asking about the actual communication process between a form and the control it contains.
I think this answer is close to what I'm looking for, but I think it's leading me down the path to using panels instead of User Controls.
After typing this I noticed the closest answer to my question may be this, but that question has the child raising events and the parent responding while I have the parent raising the event and the parent has to get information from the child.
One way to think about this is Roles. Presumably you built this UserControl to handle the management of the data related to the graphs. As such you can think of them in the Role of a Graphs Specialist . Once you do that, printing them is actually just one more thing it should perhaps do.
The form on the other hand, is not special just because it happens to get receive the command from the user to print. Its role in this might simply to be to know which usercontrol to contact and which method to invoke:
Sub PrintGraphMenuClick....
Select Case something ' determinant as to which UC to contact
Case operation.Foo
ucFoo.PrintGraph
Case operation.Bar
ucBar.PrintGraph
Other menu options like Clear, NewGraph, Save and whatever else there is somewhat the same way. The Form's Role here may be to receive the command from the user and pass it along to the right control, invoking the correct right method and passing the correct parameters - that is not a trivial task.
Of course, rather than a MainMenu, the usercontols could alternatively implement a ContextMenu and even receive those commands directly.
Very often offloading an operation to something else results in so many properties, filenames, streams etc having to be moved from here to there that it becomes burdensome. In this case it is not like the MainForm has some special ability regarding printers that the UserControl cannot handle.
There is only one right solution:
1) Add an event to your user control.
2) Raise the event when the particular "thing" happens in the user control.
3) Attach a handler to the event in Form code.
4) Add code to update the bottom bar in the event handler.
I have a form that is re-used. That is, instead of creating a new instance of the form each time, the form is kept hidden, and is made visible when needed. (A design I inherited; I presume this was a performance optimization.)
The problem: The second time that the form is used, the focus is on the OK or Cancel button, from the first use of the form.
The user wants the focus to start the way it did the first time the form appears - on the control with lowest tab index.
If there were just one such form, I would hack it: add a line of code hardwired to the desired control.
But there are many such forms, and the visibility logic is in a common base class.
So it would make more sense to do this right, and tell the form to focus on its first (lowest tabindex) control.
Is there an easy way to do so?
(I could iterate through all the controls, but then I have to correctly handle nested controls. Since the GUI has to do this the first time it shows a form, I am hoping there is some method I can call that does it for me.)
(Coded in VB.net, but a C# answer would be fine.)
It is a one-liner, the logic to find the next control is exposed as a method, SelectNextControl(). You should start at the Form object, the one that can never get the focus, and ask it to find the next one in the tabbing order. Which is the child with the lowest TabIndex, whatever value it might have.
So something like this:
public void ShowAgain() {
this.Show();
this.SelectNextControl(this, true, true, true, true);
}
And do consider that a Form object that isn't visible is a rather major resource hog, using up lots of operating system resources for a small convenience. Surely you can also Close/Dispose it and recreate it when needed. YMMV.
You can try to set ActiveControl property before making form visible:
_frm.ActiveControl = null;
This should clear the active control for the form and remove focus from its controls.
I am writing a Windows Forms application in VB.NET. I have three forms: the main form, which shows a list of accounts, the account form which allows the user to view/edit the information for a specific account, and the policy form which allows the user to view/edit the information on a specific policy for that account. I want the forms to appear as if they are all the same window. Example: when the application starts, the user clicks an account name in the list box on the main form and clicks "edit". What I want to happen is that the window stays in the exact same place and stays the same exact size, only the content of the main form appears to be replaced with the content of the account form. Same thing if the user then chooses to edit a policy from the account form. When the user finishes and clicks "save", the main form comes back up. Through this entire use case, it would appear to the user as if they were viewing the same window the entire time, with the content of that window changing.
How can I do this? I have tried something like:
Dim newForm as New AcctForm
newForm.Location = Me.Location
newForm.Show()
Me.Close()
The problem is that if the user moves the original window, the new window appears where the parent form originally appeared, not where it ended up.
I see this is already in the comments, but what I have done in this case in the past is build each "form" in the application as a custom control. Then I have one actual form, and navigation works by changing which custom control is currently loaded on the parent form. To move from one screen/view to another, you remove the current custom control from the form's controls collection and add the new custom control.
I believe this is superior to manually setting the startup position and size, because you can use the form's .SuspendLayout()/.ResumeLayout() methods to hide the interim state, where there is no control loaded, from the user. This is harder to do when you want one form to be completely replaced by another.
This also makes it easy to set certain form properties in one place and have them be consistent for the application. You can even have an area on the form with controls that will now show in every view.
When using this pattern, I typically have each of my custom controls inherit from a common base. You may not have anything specific you will do with that base at the outset, but it almost always comes in handy later.
Finally, switching to use this scheme is easier than you think. Just go to the code for the each of your current forms, and you will find that each class currently inherits from System.Windows.Forms.Form. Most of the time, all you really need to do is change them to inherit from System.Windows.Forms.Panel and you're most of the way there.
As others have said, it may be better to redesign your application using custom controls or panels etc.
However, to answer your question regarding the seemingly random location of your forms, the first thing to check is that each form has it's StartPosition property set to Manual.
If your main form is resizable, then I would also add code to adjust newForm to the same size too.
I hope that helps with your immediate issues; so that you can move on to redesigning the application!
good morning there is another way . set property for second form to (top most) and use also
from2.show();
that make you switch between forms and keep form2 top other
Thanks
try using ShowDialog()
Dim newForm as New AcctForm
newForm.Location = Me.Location
newForm.ShowDialog()
Me.Close() <-- removed this
All,
I have a TabControl in an application that started behaving strangely. Some background...
This program was converted from VB6 to VB .NET 2008, and used to refer to forms using their class names. In other words, I might have a form class called frmFoo. In the code for the program you might see:
frmFoo.Show()
or
frmFoo.UserDefinedProperty = True
During some recent changes, I created variables to represent instances of my forms much like these:
Public MyForm as frmFoo
MyForm = New frmFoo
MyForm.Show()
In doing so, I also removed code from the form's Load event handler and put it in the form's constructor.
When the form loads, or when a document is loaded and should influence the TabControl's selected index, something like the following will not necessarily fire the SelectedIndexChanged event.
MyForm.tbsForm.SelectedIndex = ValueReadFromFile
...or...
MyForm.tbsForm.Tabs(ValueReadFromFile).Select
Sorry to be so wordy, but there's more. If I open the form and look at the TabControl to verify that it's been set properly, everything works like it's supposed to. The misbehaving TabControl is contained within another TabControl, so I have to click the parent TabControl to see it. If I can see it, and run a test, the test always works. If I can't see it, and run a test, the first test I run will not fire the event. ...paging Dr. Heisenberg...
It's almost as if the control has to be initialized first by changing the value or making it visible onscreen...I'm totally lost on this one. It's the most unusual behavior I've ever seen. And everything worked perfectly before I began using variables to represent forms and placed the Load event code into the form constructors.
Can anyone help, or at least put me out of my misery?
SH
-------------------------------------------------------------- Edit #2
I just performed a test after having attempted to eliminate some of the variability in the behavior. But I wanted to confirm the previously-stated behavior.
I opened the program and read a file. This file contained a value that should have triggered the event handler. Without making the control visible, I can change the SelectedIndex property of the tab control without the event firing.
I closed the program down again, and reopened it. This time, selected the parent tab that allowed the child tab (the one whose event I'm concerned with) to become visible. I then selected a different tab in the parent control, meaning that the child control was no longer visible. When I opened the same file as before, it fired the event.
I'm tempted to implement a flag that confirms that the control has been repainted or whether the parent tab has been displayed. I may have to fire the event in code if the flag isn't set.
I want to reiterate that everything worked when the program referred to the forms by their class names and much of the arrangement of controls on the forms was done in the load event. Now the program creates variables and the arrangement of the controls is done in the form's constructor. I'm sure this has something to do with the problem I'm having, but I can't understand how. Any wisdom to share?
MyForm.tbsForm.SelectedIndexChanged = ValueReadFromFile
doesn't make a lot of sense. Is tha trying to assign a handler to the SelectedIndexChanged event? or is ValueReadFromFile the name of the tab?
What you're saying is that you have two tab controls, say, A and B. Tab control B is contained within a tab of A, and unless A has the tab page selected that contains the tab control B, the SelectedIndexChanged event of B will not fire if you change its tab programatically?
In which different ways have you tried to select a tab within the child tab control, and when is this code being executed?