I'm trying to build an Application UI using Winform for which will be having multiple pages inside it. Say software will be asking for a Login credentials on startup and then landing in a Dashboard. Then the user will have the option to go different pages like: Page1 - Page2 - Page3.
Now I'm planning to make one Form and all these pages will be separate UserControls. So as per requirement I will be changing the visibility of these UserControls.
Now to do this I'm putting the below code inside Form1.cs
ControlLogin ucLogin = new ControlLogin();
ucLogin.Location = new System.Drawing.Point(12, 67);
this.Controls.Add(ucLogin);
This works fine. But while opening any UserControl from this ControlLogin.cs how will I add the new UserControl (say Page1Control) to the list of Form1?
You need to develop some transaction logic for your pages. I suggest that on your main form you use a panel to use as container. In this container you will place current user control, the one that user selects.
For example:
internal void ReplaceUserPage(Control container, UserControl userRequest)
{
if (container.Controls.Count == 1)
{
container.Controls.RemoveAt(0);
}
container.Controls.Add(userRequest);
userRequest.Dock = DockStyle.Fill;
}
If you don't have dynamic pages, you can make all of them singletons. This way, instance of each will be created on demand and live in memory, ready to reuse. So, when user clicks on a menu or a button to open the page, you can do
UserControl requested = Page1Control.GetInstance();
ReplaceUserPage(container, requested);
With singleton, you don't even need to keep list of your controls. I don't say that this is best or perfect or one-fits-all way. There are many control transaction approaches. It depends on system complexity and other factors.
The basic layout you chose looks fine to me.
Your actual question seems to be: How to reference the form from those UCs?
This is closely related to the questions: How to reference a form or parts of it from other forms? This has been asked here very often..
Here is what I suggest you should do:
Create a public function for opening each of your UCs openLogin, openPageOne..
Change the constructors of each UC to include a Form1 as a parameter (assuming your form has the default name) and call it accordingly like this: ControlLogin ucLogin = new ControlLogin(this);
In the UCs constructors you want to store the passed in form in a class variable.
In the form you write:
public void openLogin(Form1 f)
{
ControlLogin ucLogin = new ControlLogin(this);
ucLogin.Location = new System.Drawing.Point(12, 67);
this.Controls.Add(ucLogin);
}
public void openPageOne(Form1 f)
{
..
}
And in the UC(s):
public ControlLogin(Form1 form1)
{
InitializeComponent();
mainForm = form1;
}
Form1 mainForm = null;
Now you can reference all public fields and methods in the form, maybe like this
if (logingIsOK) mainForm.openPageOne();
Related
I have a main form that includes TabControl. New forms are added as tabs in TabControl. I have trouble changing current active tab or closing tabs from forms that are not the form with TabControl. All components that i'm trying to access are Public.
Here is the code i used to change tabs:
Main mainForm = new Main();
mainForm.tcMain.SelectTab(mainForm.tpHome);
It doesn't work even if i try it to change it to index of the first tab, 0.
I also have a Label in Main form that i'm trying to change from other forms like this:
Main mainForm = new Main();
mainForm.labelStatus.Text = "Refreshed";
If it would be of any help, this is how the form i'm trying to access main form from is called
Table tableForm = new Table();
tableForm.TopLevel = false;
TabPage tableTab = new TabPage(tableForm.Text);
tcMain.TabPages.Add(tableTab);
tableForm.panelTable.Parent = tableTab;
tableForm.Parent = tableTab;
tcMain.SelectTab(tableTab);
tableForm.Show();
If you create a new Instance of Main for every property you modify, you are actually creating that many windows forms, and they have no relation to each other, They just sit in memory until they are shown to the user. What you need is a reference to the actual Main form created at the start of the application. For that, have the controls that you want to modify as public and something like below will do.
Main Class Global :
static public Main instance;
Main Class Main_Load() method :
instance = this;
In all your other forms just access main form instance like Main.instance. So this
Main mainForm = new Main();
mainForm.labelStatus.Text = "Refreshed";
will become
Main.instance.labelStatus.Text = "Refreshed";
The important thing here will be to set the access modifiers of all the controls you want to modify in the Main form to public.
If I were to navigate between 2 forms (or more), it would be like this:
Main Menu to second form:
Form2 form2 = new Form2(this) // Instantiate form and pass form data to next form
Hide();
Second form:
Form1 form;
public Form2(Form1 form1)
{
this.form1 = form1; //Take in previous form's data
}
Navigating forward will Hide() the current form while navigating backwards will Close() the current form.
But what if I am in the 3rd, 4th... nth form and I wish to go back to the main menu? Is there some kind of way to close all of my hidden forms?
Or is there a proper method to navigate between forms?
In my opinion you should use Interfaces to change data between forms. This let's you stay more independent and your Form2 just get the data it needs. For example:
public interface IForm1 //You should find better naming
{
void Edit(); //Method for edit some data
List<T> DataList {get;} //List with some relevant data
}
public Form Form1 : IForm1
{
public void Edit(){ //Your edit logic}
public List<T> DataList {get{return myGrid.DataSource as List<T>;}}
}
public Form Form2
{
private IForm1 formData;
public Form2(IForm1 formData)
{
formData = formData;
}
}
Further i would think about your idea to have so much forms. I think one MainForm with a TabControl as first element is better way to go in many cases. You can create a UserControl for each TabPage and just switch the TabPage instead of poping up Forms all the time.
UPDATE
This Picture maybe clarify what i mean. The TabPageHeader are all invisible (in image i make it visible for clarification). If Login succeed you just switch the TabPage.
TabControl.SelectedTabPage = tabPageMainScreen;
So it feels more fluent to the user and you don't have the problem you describe. But i would recommend to separate the Form by different UserControls to keep it simple.
UPDATE 2
On Winforms you can hide the TabHeader as suggested in this post.
Example:
tabControl.ItemSize = new Size(0, 1);
tabControl.SizeMode = TabSizeMode.Fixed;
It's a bit ugly that the default TabControl don't has regular way but it works fine.
I would create a view model from the data in the first form and then supply it in a method on the second form.
public class Form1ViewModel {
public int Age {get; set;}
public string Name {get; set;}
}
//method on Form1
public void NavigateToForm2()
{
var vm = new Form1ViewModel{ Age = 32, Name = "Test name"};
var form2 = new Form2();
form2.SetViewModel(vm);
form2.Show();
}
Also to close the forms take a look at this link.
I would recommend taking a look into MVVM pattern because that handles the navigation, instantiation of the forms (views). A library to start with is mvvmfx. There are also other libraries for MVVM.
While Sebi and Mihail has given great ways for a proper navigation, I have did some practice on my own and found several solutions.
As what Sebi mentioned, a TabControl with one main form is the better way to go in many cases as it is more fluent, does not have forms popping up all the time.
Another way is to only preserve the instance of your parent(main) form:
Navigating from a child form to another will pass the parent form and values of your data (if required), before closing the form (Once closed, all resources created is disposed).
However in some cases where you need to maintain the values for a previous child form (So that all user input does not need to be re-entered again), You have to also pass the child form and hide it instead of closing it.
One thing that confused me when I opened the question was that I had initially thought that navigating forward in forms should always use Hide();, and not Close();.
To close all forms except the main form (Might be useful for those who have a similar design concept as mine):
List<string> currentform = new List<string>();
foreach (Form form in Application.OpenForms)
{
if (form.Name != "Form1")
{
currentform.Add(form.Name);
}
}
foreach (string formName in currentform)
{
Application.OpenForms[formName].Close();
}
I am developing a very basic application Windows Form Application in c# that inserts values into a SQL database.
I have four separate forms
one for inputting customer details
one for inputting any transaction details
one for searching customers/transactions respectively.
What is the best way link all four forms together? I'm only just getting into C# so the most basic way possible would be ideal.
The way I see it working in my head is that you run the program and end up on one screen which shows four buttons for the four corresponding forms. When you press the button a separate window opens showing the insert forms. You can then close the form to return to the Main Start Screen
What would be the basic code for this in C#? For examples sake lets say the 5 different layouts are
Main (Containing the buttons)
TransactionEntry
AddressEntry
TransactionSearch
AddressSearch
Okay, here is an example of how I would do it. On the main form on button click event:
frmSecondForm secondForm = new frmSecondForm(this); //"this" is passing the main form to the second form to be able to control the main form...
secondForm.Show();
this.Hide();
One your Second Forms constructor code:
Form frmHome;
frmSecondForm(Form callingForm) //requires a calling form to control from this form
{
Initialize(); //Already here
frmHome = callingForm as frmMain;
}
Then on the second form's closing unhide the main form:
frmSecondForm_FormClosing()
{
frmHome.Show();
}
So all in all, if you needed to pass data between the forms just add it as a parameter on the second form.
Again, I would consider placing your data collection into a repository package (folder) and class, then create a User.cs class that will hold all of the information you keep in the database.
Hint: Right click your top level item in solution explorer and go to New -> Folder. Name it Repo.
Right click that folder and go to New -> Class and name it UserRepo.
In here build functions to collect the data from the databases.
On your main form's constructor area, call the class (repo).
private Repo.UserRepo userRepo;
frmMain_FormLoad()
{
userRepo = new Repo.UserRepo();
}
Then on log in button click:
private button1_ClickEvent()
{
if(userRepo.isValidLogin(userNameText, passwordText))
{
//Do stuff
}
}
for userRepo.isValidLogin()
public bool isValidLogin(String username, String password)
{
bool isValid = false;
//Write up data code
return isValid;
}
From the Main form use eg:
TransactionEntry trans = new TransactionEntry();
trans.ShowDialog();
.ShowDialog() will show the new form, but will halt any code executing on the Main form until you close it
(This assumes your forms are all in the same solution)
You could try the MDI (Multiple Document Interface) way, here is a nice tutorial: http://www.dreamincode.net/forums/topic/57601-using-mdi-in-c%23/
I have two forms in C# Window application as frm_Stock.cs and frm_Purchase.cs.
I want to use some controls of frm_Stock in the frm_Purchase.Is it possible?IF yes then how can i do this please give me suitable example.
Thanks in advance
You will have to pass a reference to the controls/form when constructing the other form, and use that reference. A rough example,
frm_Stock = new StockForm();
frm_Purchase = new PurchaseForm(frm_Stock);
then within the purchase form code...
public class PurchaseForm : Form
{
public PurchaseForm(StockForm frm_Stock)
{
frm_Stock.SomeControl.Text = "blah";
}
}
It is possible but not recommended way of doing it, you should have pass it to the other form via some shared object(i-e StateBag ). You can make the controls of Frm_Stock public and then they will be accsible from frm _Purchase when you make frm_Stock instance.
You should create a custom user control and use it on both forms.
If you want to share the same instance of the user control across the form, then create an instance when your application starts and add it manually on both forms when they load.
I'm rewriting an old application and use this as a good opportunity to try out C# and .NET development (I usually do a lot of plug-in stuff in C).
The application is basically a timer collecting data. It has a start view with a button to start the measurement. During the measurement the app has five different views depending on what information the user wants to see.
What is the best practice to switch between the views?
From start to running?
Between the running views?
Ideas:
Use one form and hide and show controls
Use one start form and then a form with a TabControl
Use six separate forms
Creating a bunch of overlaid panels is a design-time nightmare.
I would suggest using a tab control with each "view" on a separate tab, and then picking the correct tab at runtime. You can avoid showing the tab headers by putting something like this in your form's Load event:
tabControl1.Top = tabControl1.Top - tabControl1.ItemSize.Height;
tabControl1.Height = tabControl1.Height + tabControl1.ItemSize.Height;
tabControl1.Region = new Region(new RectangleF(tabPage1.Left, tabPage1.Top, tabPage1.Width, tabPage1.Height + tabControl1.ItemSize.Height));
What I do is to have a Panel where your different views will sit on the main form.
then create user controls for your different views.
Then when I want to switch between a'view' you dock it to Panel on the main form.. code looks a little like this.
i preffer this because you can then reuse your views, like if you want to open up a view in a tab you can dock your user controls inside tab pages.. or even inherit from
tabpage instead of usercontrol to make things a bit more generic
public partial class MainForm : Form
{
public enum FormViews
{
A, B
}
private MyViewA viewA; //user control with view a on it
private MyViewB viewB; //user control with view b on it
private FormViews _formView;
public FormViews FormView
{
get
{
return _formView;
}
set
{
_formView = value;
OnFormViewChanged(_formView);
}
}
protected virtual void OnFormViewChanged(FormViews view)
{
//contentPanel is just a System.Windows.Forms.Panel docked to fill the form
switch (view)
{
case FormViews.A:
if (viewA != null) viewA = new MyViewA();
//extension method, you could use a static function.
this.contentPanel.DockControl(viewA);
break;
case FormViews.B:
if (viewB != null) viewB = new MyViewB();
this.contentPanel.DockControl(viewB);
break;
}
}
public MainForm()
{
InitializeComponent();
FormView = FormViews.A; //simply change views like this
}
}
public static class PanelExtensions
{
public static void DockControl(this Panel thisControl, Control controlToDock)
{
thisControl.Controls.Clear();
thisControl.Controls.Add(controlToDock);
controlToDock.Dock = DockStyle.Fill;
}
}
Tabbed forms are usually good... but only if you want the user to be able to see any view at any time... and it sounds like you might not.
Separate forms definitely works, but you need to make sure that the switch is seemless...if you make sure the new form appears the same exact size and location of the old form, it will look like it thew same for with changing controls.
The method I often use is actually to pre-setup all my controls on individual "Panel" controls and then show and hide these panels as I need them. The "Panel" control is basically a control container... you can move the panel and all controls on it move relative. And if you show or hide the panel, the controls on it do the same. They are great for situations like this.
The method I often use is actually to
pre-setup all my controls on
individual "Panel" controls and then
show and hide these panels as I need
them.
Instead of making each view a panel within a single form you could make each view a UserControl. Then create a single form and write code to create and display the correct UserControl in the Form and to switch from one to the next. This would be easier to maintain because you will have a separate class for each view instead of a single Form class with 6 panels each with their own controls -- that seems difficult and error prone to maintain.
I would also check out Composite Application Guidance for WPF or Smart Client Software Factory