I've following Winforms.
frmBase
frmChild1, frmChild2.....,frmChild20
Totally 21 Forms. From frmBase, I'll call all other forms on Button click based on condition. All are having 3 set of parameters. Eg:
frmChild1 objForm = new frmChild1();
objForm.strName = txtName.Text1;
objForm.strAddr = txtAddress.Text2;
objForm.strCity = txtCity.Text2;
objForm.ShowDialog();
If I call all forms like this, I've huge amount of coding. Since only Form name is changing, is there anyother simple way to call all 20 forms from Base form button click.
You could try the below code.
Solution 1:
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class ObjectFinder
{
private static object CreateObjectInstance(string objectName)
{
// Creates and returns an instance of any object in the assembly by its type name.
object obj = null;
try {
if (objectName.LastIndexOf(".") == -1) {
//Appends the root namespace if not specified.
objectName = string.Format("{0}.{1}", Assembly.GetEntryAssembly.GetName.Name, objectName);
}
obj = Assembly.GetEntryAssembly.CreateInstance(objectName);
} catch (Exception ex) {
obj = null;
}
return obj;
}
public static Form CreateForm(Form objForm, string strName, string strAddr, string strCity)
{
// Return the instance of the form by specifying its name.
var objChild = (objForm)CreateObjectInstance(objForm.Name);
objChild.strName = txtName.Text1;
objChild.strAddr = txtAddress.Text2;
objChild.strCity = txtCity.Text2;
return objChild;
}
}
You could call this static function to create child form as below
objForm = ObjectFinder.CreateForm(frmChild1, strName, strAddr, strCity);
objForm.ShowDialog();
Solution 2:
or, Simply create extension method of Form object as below.
public static Form CreateForm(this Form objForm, string strName, string strAddr, string strCity)
{
// Return the instance of the form by specifying its name.
var objChild = (objForm)CreateObjectInstance(objForm.Name);
objChild.strName = txtName.Text1;
objChild.strAddr = txtAddress.Text2;
objChild.strCity = txtCity.Text2;
return objChild;
}
and, call this extension method as below
objForm = frmChild1.CreateForm(strName, strAddr, strCity);
objForm.ShowDialog();
The forms should implement a common interface (that you define), then you can iterate through the list of Interfaces (regardless of what implementation each form has for the interface. and do the stuff you want. For example something like this:
public interface IMyForm
{
string strName { get; set; }
string strAddress {get; set; }
string strCity { get; set; }
void ShowDialog();
}
then if all of your forms implement that interface your main form can keep a list of all its child forms in a list of IMyForm and just loop through and assign/show all the things.
If all the forms have the same control you could also write a base Form and inherit the other forms from that form and maintain the same kind of list.
If the forms just differ in text in the title, you should write 1 form that has the controls all your form instances will need and just pass different form titles into its creation.
Depend on what is your need but you should consider adding all the forms in a List<Form> creating a method or work on the constructor.
The advantage could be that you can call them with an enumerator or a foreach
Expanding on Skintkingle's answer,
You can add a Dictionary<object, Func<IMyForm>> to your main form, that will hold the selected item of the dropdown as it's key, and the constructor of the form as it's value:
private Dictionary<object, Func<IMyForm>> _SubForms = new Dictionary<object, Func<IMyForm>>()
{
{"Form1", () => {return new Form1();}},
{"Form2", () => {return new Form2();}
//....
};
And then, in your button click, all you need to do is this:
var selectedItem = MyDropDown.SelectedItem;
if(_SubForms.ContainsKey(selectedItem)
{
var form = _SubForms[selectedItem]();
form.strName = txtName.Text1;
form.strAddr = txtAddress.Text2;
form.strCity = txtCity.Text2;
form.ShowDialog();
}
Related
I'm currently developing a Windows Form Application that uses two forms. I have no problems linking between the two forms. My issue is accessing a variable in Form2 that was created in Form1. How do you make a variable accessible to multiple forms in the same project?. I honestly tried to look for an answer, but could not find anything. Any help would be appreciated.
Here is the code for Form1:
namespace HourlyAlarm1
{
public partial class AlarmToneSetter : Form
{
public bool halfHourSelected;
public AlarmToneSetter()
{
InitializeComponent();
}
private void okButton_Click(object sender, EventArgs e)
{
if(halfHourRadio.Checked)
{
halfHourSelected = true;
}
else
{
halfHourSelected = false;
}
Form1 f1 = new Form1();
f1.ShowDialog();
}
public bool getHalfHourSelect()
{
return halfHourSelected;
}
}
}
Here is the code for Form2:
namespace HourlyAlarm1
{
public partial class Form1 : Form
{
int min;
System.Media.SoundPlayer sp;
public Form1()
{
InitializeComponent();
}
private void playSound()
{
sp = new System.Media.SoundPlayer(HourlyAlarm1.Properties.Resources.chipfork);
sp.Load();
sp.Play();
}
private void timer1_Tick(object sender, EventArgs e)
{
TimeLabel.Text = DateTime.Now.ToLongTimeString();
min = DateTime.Now.Minute;
if(HourlyAlarm1.AlarmToneSetter.g)
if(min == 0)
{
playSound();
}
}
}
}
If you want a variable which is accessible to any form within the project, mark it as static. That way you don't need a specific instance of the class that it's in to be able to access it.
You can use the forms Tag property if you want to pass just one variable.
Form1 f1 = new Form1();
f1.Tag="some value";
f1.ShowDialog();
and then in form 2 access it via it's own Tag property. Since it is stored as an object you will have to convert it to whatever datatype your application requires.
Example for getting the value in the new form:
string value = this.Tag.ToString();
As the question currently stands, it looks like you're trying to edit the halfHourSelected field in your AlarmToneSetter class from the Form1 class. To do that, there are several options:
Since this field is already public you can simply edit it like this (form Form1):
HourlyAlarm1.AlarmToneSetter.halfHourSelected = true;
or, if you plan on using it several times, add
using HourlyAlarm1;
/**
* declare the namespace, the class, etc.
*/
AlarmToneSetter.halfHourSelected = true
(Edit: As mentioned by Jason, this can be rewritten to be a property and comply with the style guide) However, since you already wrote a Java-style getter for this field, you should rewrite it in C# style; changing the declaration to
public bool HalfHourSelected{get;set;};
which will add the getter and setter for the property automatically.
Now, if you want to make this field persistent (that is, the configuration value should be saved across multiple executions of the program) then you should consider adding it to the settings of your project, and reference it like this
HourlyAlarm1.Properties.Settings.Default.halfHourSelected = true;
HourlyAlarm1.Properties.Settings.Default.Save();
or, as always, if you're gonna access them several times,
using HourlyAlarm1.Properties;
/**
* declare the namespace, the class, etc.
*/
Settings.Default.halfHourSelected = true;
Settings.Default.Save();
Yes, this is my first time answering a question in SO. If you have any recommendations, let me know in the comments! I'll appreciate the feedback.
Pass them as parameter of constructor. This way is used to set once time at creating an instance of class
public Form1(int i, string s, object o){}
Create public get/set. This way is used to set multiple times, but their value will be different among instances of class.
public int Price { get; set;}
Form1 frm1 = new Form1();
frm1.Price = 123;
Create public static field. This way is used to set multiple times, and it is same among instance of class.
public static int Price = 0;
Form1.Price = 123;
First of all public fields are discouraged in .NET: you should use properties.
Your problem is that bool is a value type and you can't "bind" it between forms, you need a reference type.
public class ReferenceBoolean
{
public bool Value{get;set;}
}
public class Form1
{
protected ReferenceBoolean HalfHourSelectedReference{get;set;}
public bool HalfHourSelected
{
get{return this.HalfHourSelectedReference.Value;}
set{this.HalfHourSelectedReference.Value = value;}
}
public Form1()
{
this.HalfHourSelectedReference = new ReferenceBoolean();
}
}
public class Form2
{
protected ReferenceBoolean HalfHourSelectedReference{get;set;}
public bool HalfHourSelected
{
get{return this.HalfHourSelectedReference.Value;}
set{this.HalfHourSelectedReference.Value = value;}
}
public Form2(ReferenceBoolean halfHourSelected)
{
this.HalfHourSelectedReference = value;
}
}
Now this might look all fine and dandy but there is one thing I did not do, because I'm not sure if you need it, if you update this value and have it bound to the UI in your form the update will not be reflected in the form. To do that you must implement something like the IPropertyNotificationChange pattern, which works much better in WPF.
I am accesing another file by doing this:
public void startUpdateChecking()
{
UpdateHandler process = new UpdateHandler();
process.initialize(this);
}
The same class that 'startUpdateChecking' function is in I have this example functon aswell:
public void changeText(string Text)
{
label2.Text = Text;
}
Now in the UpdateHandler class I am doing this:
public Form form;
public void initialize(Form test)
{
Thread update = new Thread(checkForUpdates);
update.Start();
form = test;
edit();
}
public void edit() {
form.changeText("test");
}
But 'form' has no clue what changeText is for some reason, how would I make it so I can use functions from another class (Form2 class) WITHOUT the need for static function?
I tried doing:
Form2 form = new Form2();
And I could control and acces things from Form2, but this makes a new form instead of controlling the current one that is active (aka nothing visible happends using this).
Thanks in advance.
One way would be to use a delegate to pass the changeText method instead of passing the whole form. This should help separate the classes and I think would improve the design.
A quick way of doing this would use an action. Instead of passing in Form to initialize pass Action<Text>
The form side code would change to
public void startUpdateChecking()
{
UpdateHandler process = new UpdateHandler();
process.initialize((s) => {changeText(s);});
}
and the UpdateHandler side code would change to
public void initialize(Action<string> outputMethod)
{
Thread update = new Thread(checkForUpdates);
update.Start();
output= outputMethod;
edit();
}
public void edit() {
output("test");
}
Try to return a value from initialize and then pass that on to ChangeText.
like this:
public void startUpdateChecking()
{
UpdateHandler process = new UpdateHandler();
string Value1 = process.initialize(this);
ChangeText(Value1);
}
Initialize should then be a string, im not sure what the form is doing there, and what it has to do with the Thread update, thats something you probably know more about
public string initialize(string test)
{
Thread update = new Thread(checkForUpdates);
update.Start();
form = test;
return test;
}
Just don't try to call a function from out a class, best way is to return from a class and then call a function
I have Gridview in my Form, If i click button on the Gridview I get Column value of Focused Row and Try to use that Value in next Form. But in that new form error shown like this
public partial class New_Invoice : DevExpress.XtraEditors.XtraForm
{
string getOper = "A";
public New_Invoice()
{
InitializeComponent();
}
public New_Invoice(string oper, int invoiceno)
{
// TODO: Complete member initialization
textEdit5.Text = invoiceno.ToString(); // error shown in this line
textEdit5.Visible = false;
getOper = oper;
}
What was wrong in my code ?
In your custom constructor you aren't calling InitializeComponent(). This is critical: this is what creates the controls. A simple fix might be to chain the constructor (see the : this()):
public New_Invoice(string oper, int invoiceno) : this()
{
textEdit5.Text = invoiceno.ToString(); // error shown in this line
textEdit5.Visible = false;
getOper = oper;
}
However, personally I would advise against adding custom constructors to forms / controls, and instead use properties / methods on the newly created instance, so the caller does something like:
using(var form = new NewInvoice())
{
form.Operation = ...; // (or maybe form.SetInvoiceNumber(...) if the
form.InvoiceNumber = ...; // logic is non-trivial)
// show the form, etc
}
I tried to search for an answer to this but I couldn't find one, the closest I found was: Create an instance of a class from a string but it doesn't really answer my question:
How do I create an instance of a class from a string, e.g. I want to create a WinForms object and add it to MDI.
I have a function that accepts a string, formname (e.g. "Form1"), and checks MDI children for an instance, if it exists it sets focus, if not then it creates an instance and adds it to the children.
The way I currently create a form is with a case statement but I will have to update this every time I add new Forms to the project! Is there a way of adding an instance of a Form class to the MDI children based on the string passed in, e.g. pseudo-code:
call to function:
openForm("Form2");
public void openForm(String formname)
{
if form exists in MDI children
{
focus form with name = formname;
}
else
{
MDIChildren.add(CreateInstanceOfClassNamed(formname));
}
}
try something like this (pseudocode, no clue about MDI stuff)
public void openForm(String formTypeName)
{
Form FocusForm = null;
Type formType = Type.GetType(formTypeName);
foreach (var form in MDIChildren)
{
if (form.GetType() == formType)
{
focusForm = form;
break;
}
}
if (focusForm == null)
{
MDIChildren.add(Activator.CreateInstance(formType));
}
// set focus to focusForm
}
Activator can create object from class name:
object obj = Activator.CreateInstance(Type.GetType(assemblyname + "." +formname));
((Form)obj).ShowDialog();
Rather than passing a string you can just make the function generic:
public TForm GetForm<TForm>()
where TForm : Form, new()
{
TForm existingChild = MDIChildren.OfType<TForm>().FirstOrDefult();
if(existingChild != null)
{
//focus, or do whatever
return existingChild;
}
else
{
TForm newChild = new TForm();
//do stuff with new child
return newChild;
}
}
This will ensure that you don't pass the string value of a class that isn't a Form, or isn't of any type at all. You could call it like:
Form2 newChild = GetForm<Form2>();
In code behind file of the main window of WPF application I have a method quering a database with LINQ to SQL and writing results to an ObservableCollection:
public void GetStateByDate(string shcode)
{
MydbDataContext contextSts = new MydbDataContext();
_ShAvaQuCollection.Clear();
var sts = from p in contextSts.SAties where p.ShID == shcode select p;
foreach (var p in sts)
_ShAvaQuCollection.Add(new ShAvaQu
{
ShCode = p.ShID,
SiID = p.SiID,
PrCat = p.PrCat
});
}
When I call this method from the same code behind file (the same window), everything is OK.
If I call this method from another window, using an instanse of the main window, ObservableCollection remains empty.:
SWindow sw = new SWindow();
sw.GetStateByDate(stringpar);
What is the reason for this? Does in this case method create yet another instance of ObservableCollection?
(I can see in debugger that sw._ShAvaQuCollection contains values. Is sw._ShAvaQuCollection not the same instanse of collection as _ShAvaQuCollection? If yes, how it can be resolved?)
Edited (added)
The ObservableCollection declared this way:
ObservableCollection<ShAvaQu> _ShAvaQuCollection =
new ObservableCollection<ShAvaQu>();
public ObservableCollection<ShAvaQu> ShAvaQuCollection
{ get { return _ShAvaQuCollection; } }
public class ShAvaQu
{
public string ShCode { get; set; }
public string SiID { get; set; }
public int PrCat { get; set; }
}
I call the method from a window, where another collection ShQuCollection displayed through ListView. In SelectionChanged event handler I take an argument for this database quering:
private void ShSelList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SWindow sw = new SWindow();
string str = sw.ShQuCollection[ShSelList.SelectedIndex].ShCode;
sw.GetStateByDate(str);
Close();
}
}
1) Most importantly you shouldn't be calling db logic from you windows / forms. You should abstract it out into another class. Then you could have your method return a observable collection.
However in your case I am assuming that you are trying to use the secondary form to reload / load the collection and you want it used on your primary form. The problem with this is you are creating a new instance of the form so your collection is being populated but not on your main form but a copy.
There are a couple ways you can try to get around that.
1) Make the method static and your observable collection static so that it updates a single instance.
2) Pass an instance handle of your primary form into your secondary form so that you re-use the instance you already have. This would be preferable so that you are not creating new instances all over the place.
In the constructor of the second form you could pass in the instance of your primary window so then you can use it directly. This should solve your problem.
UPDATE: Here is some code samples. Basically there are many ways to pass a reference.
You could do it like this with a constructor:
// This is the constructor for your second window
private Window _parentHandle;
public SecondWindow(Window obj)
{
this._parentHandle = obj;
}
Then from your primary form that has the method you would open that window like this.
SecondWindow w = new SecondWindow(this);
w.Show();
Now your second window has a direct handle to your first window so you can call your method on that variable and it will update.
Another way is to have a public Setter method on your second window as well.
public Window ParentContext
{
get { return this._parentHandle; }
set { this._parentHandle = value; }
}
Then you could create your form instance like this:
SecondWindow w = new SecondWindow(); // so just like normal
w.ParentContext = this; // set the instance to the calling form
w.Show();
That is the basics. This type of scenario works in just about any scenario where you need to pass a reference.
Hope that helps.