I have a .NET CF program (running on a Smartphone) and I have written an options page for it.
On the options page I have links to 6 other forms which contain the actual options.
When the main form loads it creates the 6 subforms and stores them in a list ready to be launched. The issue with this is the initial creation time required to make these forms, which makes the main settings form slow.
What I would ideally like, is a way to just specify the type and parameters required to create the subform on load, then actually create the form when needed.
Here is code snippets of how it currently works:
Form_OnLoad():
AddSettingsOptions("General", new General());
AddSettingsOptions("Action Alert", new BaseAlertForm("Action Alert Settings", SystemManager.ActionAlert));
AddSettingsOptions("Comms Alert", new BaseAlertForm("Comms Alert Settings", SystemManager.CommsErrorAlert));
AddSettingsOptions("Advanced", new Advanced());
AddSettingsOptions("Diagnostics", new Diagnostics(_unitWatcher));
AddSettingsOptions("About", new About());
The form is stored in the Tag section of a list (which displays the sub options)
private void AddSettingsOptions(String name, Form form)
{
listViewSettings.Items.Add(
new ListViewItem(
String.Format(" {0} {1}", listViewSettings.Items.Count + 1, name))
{
Tag = form
}
);
}
If an option is pressed the following function is called to launch the form
private void ShowSubSetting(ListViewItem item)
{
if (item == null)
return;
object tag = item.Tag;
Form form = tag as Form;
if (form != null)
{
form.ShowDialog();
//form.Dispose();
}
}
I'm sure there is a pretty easy way to do this, I'm just struggling with the correct way.
Thanks
You can do it this way:
AddSettingsOptions("General", ()=> new General() );
AddSettingsOptions("Action Alert", ()=> new BaseAlertForm("Action Alert Settings", SystemManager.ActionAlert) );
// etc ...
void ShowSubSettings(ListViewItem item ){
if ( null == item ) { continue; }
object tag = item.Tag;
Func<Form> func = tag as Func<Form>;
if ( null != func ) {
Form frm = func();
if ( null != frm ) {
frm.ShowDialog();
}
}
}
If you are using C# 2.0, you must use
delegate { return new General(); }
instead of
()=> new General();
Related
I have a total of 6 forms. In my mainForm, I have 5 buttons to open the other forms inside the panel. what i know is something like this:
form1 f1 = new form1();
f1.TopLevel = false;
f1.Dock = DockStyle.Fill;
this.panelMid.Controls.Add(f1);
f1.show();
now, since I have 5 other forms, I want to make a function that would make me open the forms without re-typing those code in every button event.
My problem is that I don't know to pass the form into a function as parameter.
DRY 101, based on your code, with some generics chucked in
public void MyAwesomeFormShower<TForm>()
where TForm : Form, new()
{
var form = new TForm();
// common code here
form.TopLevel = false;
form.Dock = DockStyle.Fill;
///this.panelMid.Controls.Add(f1); // < who knows what this does, however don't do it
form.Show();
}
Usage
MyAwesomeFormShower<MyLovelyHorseForm>();
Or if you want to get fancy
public void MyAwesomeFormShower<TForm>(Action<TForm> action = null)
where TForm : Form, new()
{
var form = new TForm();
// common code here
form.TopLevel = false;
form.Dock = DockStyle.Fill;
action?.Invoke();
form.Show();
}
Usage
MyAwesomeFormShower<MyLovelyHorseForm>();
// or
MyAwesomeFormShower<MyLovelyHorseForm>((form) =>
{
// Specialised form stuff here
// that is specific to MyLovelyHorseForm
});
My problem is that I have created child's object and show child first time. but when second time I just want to change value of child's label from parent but don't want to show another form.
Here is my code.
First time
ChildForm ObjChild = new ChildForm("Hi");
ObjChild.Show();
On second time I just want to set Bye in place of Hi.
ChildForm ObjChild = new ChildForm("H!");
ObjChild.BringToFront();
Because child form is already opened.
This is my child Form
public Form1(string p_Param)
{
InitializeComponent();
Label1.Text = p_Param;
}
Constructors call one time when object created. You must implement a new public void or function rather than a constructor to do that.
public void ChangeLabelText(string txt)
{
Label1.Text=txt;
}
EDIT:
In your parent form;
Out of functions;
chilFrm ChildForm;
Inside any function;
if (chilFrm == null)
{
chilFrm = new ChildForm();
chilFrm.TopLevel = false;
chilFrm.Parent = this;
chilFrm.StartUpProsecc("Created New");
chilFrm.Show();
}
else
{
chilFrm.StartUpProsecc("Showed the existing.");
chilFrm.BringToFront();
}
i have treeview which each node tag contain form name , when i click on node i open the form
my code is as follows
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
NodeClick(Convert.ToString(e.Node.Tag));
}
public void NodeClick(string formName)
{
switch (formName)
{
case "frmPartMaster":
frmPartMaster partMaster = null;
if ((partMaster =
(frmPartMaster)Globale.IsFormAlreadyOpen(typeof(frmPartMaster)))
== null)
{
partMaster = new frmPartMaster();
partMaster.Show(this);
}
else
{
partMaster.Activate();
partMaster.WindowState = FormWindowState.Normal;
partMaster.BringToFront();
}
break;
}
}
this code is working fine but i have 1000's of form , for each for form i have to right case the code.
is it possible if i passed the form it open it open like in single case?
You can create instance of a form class by the call of Activator.CreateInstance
public void OpenOrActivateForm(string formType)
{
var formType = Type.GetType(formType);
var form = Globale.IsFormAlreadyOpen(formType);
if(form == null)
{
form = Activator.CreateInstance(formType);
from.Show(this);
}
else
{
form.Activate();
form.WindowState = FormWindowState.Normal;
form.BringToFront();
}
}
Why don't you just put a reference to a form in the Node's Tag and then use that directly
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
NodeClick(e.Node.Tag as Form);
}
public void NodeClick(Form theForm)
{
if(theForm == null) return;
if(theForm.Visible == false)
{
theForm .Show(this);
}
theForm .Activate();
theForm .WindowState = FormWindowState.Normal;
theForm .BringToFront();
}
You should be able to add the form to the node, the node should have a field, tag i think it is that is of type object. Add your form there then extract it from the tag. That way you will not have to use a case statement but 1 single statement that works for all forms.
Instead of using switch case for every form, you can use Activator.CreateInstance method.
Refer this MSDN Article.
You can store Fully Qualified Name in the tag and use it to instantiate appropriate form.
You could use this approach:
Define a Dictionary of strings and actions like this
Dictionary<string, Action> dic = new Dictionary<string,Action>();
dic.Add("frmPartMaster", OpenPartMaster);
.....
add the appropriate action
private void OpenPartMaster()
{
frmPartMaster partMaster = null;
if ((partMaster =
(frmPartMaster)Globale.IsFormAlreadyOpen(typeof(frmPartMaster)))
== null)
{
partMaster = new frmPartMaster();
partMaster.Show(this);
}
else
{
partMaster.Activate();
partMaster.WindowState = FormWindowState.Normal;
partMaster.BringToFront();
}
}
and when you need to call that form instead of an infinite switch use
dic[formName].Invoke();
in this way you have a centralized point where you add the specific action to execute when a particular form is requested and you keep all the functionality already written.
Of course you need to refactor the switch cases in separate methods.
This approach is interesting if you have different actions (cases) for your form and not a always the same sequence of repeating code.
I am using a method sice I will have alot of child forms. Now it does show when I call a form by clicking on a button, but not after the login child is closed.
Method:
private void mForms(Form f)
{
if (this.MdiChildren.Contains(f))
{
f.WindowState = FormWindowState.Normal;
}
else
{
f.MdiParent = this; f.Show();
}
}
This just simply checks if the MDIcontainer already contains the requested form. If yes, put it back up again (in case it's minimized), if not, show it.
Now I can call the forms using this:
private void ts_bestand_studenten_add_Click(object sender, EventArgs e)
{
if (add_student.IsDisposed)
{
add_student = new add_student();
}
mForms(add_student);
}
This checks if it is disposed already or not. If so, redefine it. Then it calls to the method to open the right form. This works as it should.
Now the problematic part:
After the login screen is closed and user is logged in, the userlevel is defined. I should be able to open another form. This is the method I use for that: (NOTE: the userlevels work fine since it does reach the Messagebox)
// Predefines start_screen_admin
Form start_screen_admin = new start_screen_admin();
public void mCommitRights()
{
if (userlevel.gCheckLevel == 0)
{
// Admin, no changes
MessageBox.Show("Admin");
mForms(start_screen_admin);
}
... more of the same to check for userlevels
}
Now you think this should work. I don't have to redefine it because it's the first time it opens and it is already predefined. The MessageBox shows, but the form does not. I really can't see a problem in this. I tried everything I could think of..
I think you need to include the Select() method to bring the form to the front:
Try changing it to this:
private void mForms(Form f) {
if (this.MdiChildren.Contains(f)) {
f.WindowState = FormWindowState.Normal;
f.Select();
} else {
f.MdiParent = this;
f.Show();
}
}
I want to restrict the user to create multiple instances of a form in an MDI application.
If one instance of that form is opened it must get focus. If it is not a new instance it must be created.
How can I do this?
You can do it like this.
Create a static Method:
public static Form IsFormAlreadyOpen(Type FormType)
{
foreach (Form OpenForm in System.Windows.Forms.Application.OpenForms)
{
if (OpenForm.GetType() == FormType)
return OpenForm;
}
return null;
}
And then when you create your child form.
frmMyChildForm frmChild1;
if ((frmChild1 = (frmMyChildForm)IsFormAlreadyOpen(typeof(frmMyChildForm))) == null)
{ //Form isn't open so create one
frmChild1= new frmMyChildForm ();
}
else
{ // Form is already open so bring it to the front
frmChild1.BringToFront();
}
You could use a singleton-pattern-approach, and let the form have an Instance-member-variable that keeps track of whether it's been initialized or not.
http://en.wikipedia.org/wiki/Singleton_pattern
Maybe something like this could help you
Form frmToCreate;
String strClassName=typeof(FormToCreate).Name
frmToCreate = GetForm(strClass);
if(frmToCreate == null)
{
//create the form here
}
frmToCreate.MdiParent = this; //supposing you are inside of the mainwindow (MDI window)
frmToCreate.Visible = true;
//other code goes here
where GetForm would be something like this
public Form GetForm(String type)
{
int i;
Form[] children = this.MdiChildren; //or mdiwindow.MdiChildren
for (i = 0; i < children.Length; i++)
{
if (children[i].GetType().Name == type)
{
return children[i];
}
}
return null;
}
If just a matter of playing with MdiChildren property.