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.
Related
From what i've read so far i've done this:
On my first form:
public partial class FPrincipal : Form
{
List<Grua> ListaGruas = new List<Grua>();
List<Semirremolques> ListaSemirremolques = new List<Semirremolques>();
List<Clientes> ListaClientes = new List<Clientes>();
// this is the menu strip i click to create my new form,
// send my list and add my values
private void miEquipoCargar_Click(object sender, EventArgs e)
{
EquiposCargar FormEquiposCargar = new EquiposCargar(ListaGruas);
FormEquiposCargar.ShowDialog();
}
}
And on my second form:
public partial class EquiposCargar : Form
{
// I saw some videos on youtube and this is how the pass some values,
// but it doesnt work with lists
public EquiposCargar(List<Grua>listaGrua)
{
InitializeComponent();
}
}
Could anyone please help me? im stuck.
The error says the parameter List<Grua>listaGrua is less accesible than the method EquiposCargar.EquiposCargar(List<Grua>)
just another question! how do i use the list on my second form? lol...
because it says the name listaGrua is not defined in the actual
content. It looks like i have to create a new variable and assign the
list parameter than i sent, right? but im doing it and its still not
working
That's correct, you need to create a variable in your second form to hold that reference. In the constructor, simply assign the passed in reference to your form's reference:
public partial class EquiposCargar : Form
{
private List<Grua> listaGrua;
public EquiposCargar(List<Grua> listaGrua)
{
InitializeComponent();
this.listaGrua = listaGrua;
}
}
Note the use of the this keyword. Now you should be able to use listaGrua from anywhere in your second form.
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();
}
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
}
How do I pass a value from a child back to the parent form? I have a string that I would like to pass back to the parent.
I launched the child using:
FormOptions formOptions = new FormOptions();
formOptions.ShowDialog();
Create a property (or method) on FormOptions, say GetMyResult:
using (FormOptions formOptions = new FormOptions())
{
formOptions.ShowDialog();
string result = formOptions.GetMyResult;
// do what ever with result...
}
If you're just using formOptions to pick a single value and then close, Mitch's suggestion is a good way to go. My example here would be used if you needed the child to communicate back to the parent while remaining open.
In your parent form, add a public method that the child form will call, such as
public void NotifyMe(string s)
{
// Do whatever you need to do with the string
}
Next, when you need to launch the child window from the parent, use this code:
using (FormOptions formOptions = new FormOptions())
{
// passing this in ShowDialog will set the .Owner
// property of the child form
formOptions.ShowDialog(this);
}
In the child form, use this code to pass a value back to the parent:
ParentForm parent = (ParentForm)this.Owner;
parent.NotifyMe("whatever");
The code in this example would be better used for something like a toolbox window which is intended to float above the main form. In this case, you would open the child form (with .TopMost = true) using .Show() instead of .ShowDialog().
A design like this means that the child form is tightly coupled to the parent form (since the child has to cast its owner as a ParentForm in order to call its NotifyMe method). However, this is not automatically a bad thing.
You can also create a public property.
// Using and namespace...
public partial class FormOptions : Form
{
private string _MyString; // Use this
public string MyString { // in
get { return _MyString; } // .NET
} // 2.0
public string MyString { get; } // In .NET 3.0 or newer
// The rest of the form code
}
Then you can get it with:
FormOptions formOptions = new FormOptions();
formOptions.ShowDialog();
string myString = formOptions.MyString;
You can also create an overload of ShowDialog in your child class that gets an out parameter that returns you the result.
public partial class FormOptions : Form
{
public DialogResult ShowDialog(out string result)
{
DialogResult dialogResult = base.ShowDialog();
result = m_Result;
return dialogResult;
}
}
Use public property of child form
frmOptions {
public string Result; }
frmMain {
frmOptions.ShowDialog(); string r = frmOptions.Result; }
Use events
frmMain {
frmOptions.OnResult += new ResultEventHandler(frmMain.frmOptions_Resukt);
frmOptions.ShowDialog(); }
Use public property of main form
frmOptions {
public frmMain MainForm; MainForm.Result = "result"; }
frmMain {
public string Result;
frmOptions.MainForm = this;
frmOptions.ShowDialog();
string r = this.Result; }
Use object Control.Tag; This is common for all controls public property which can contains a System.Object. You can hold there string or MyClass or MainForm - anything!
frmOptions {
this.Tag = "result": }
frmMain {
frmOptions.ShowDialog();
string r = frmOptions.Tag as string; }
Well I have just come across the same problem here - maybe a bit different. However, I think this is how I solved it:
in my parent form I declared the child form without instance e.g. RefDateSelect myDateFrm; So this is available to my other methods within this class/ form
next, a method displays the child by new instance:
myDateFrm = new RefDateSelect();
myDateFrm.MdiParent = this;
myDateFrm.Show();
myDateFrm.Focus();
my third method (which wants the results from child) can come at any time & simply get results:
PDateEnd = myDateFrm.JustGetDateEnd();
pDateStart = myDateFrm.JustGetDateStart();`
Note: the child methods JustGetDateStart() are public within CHILD as:
public DateTime JustGetDateStart()
{
return DateTime.Parse(this.dtpStart.EditValue.ToString());
}
I hope this helps.
For Picrofo EDY
It depends, if you use the ShowDialog() as a way of showing your form and to close it you use the close button instead of this.Close(). The form will not be disposed or destroyed, it will only be hidden and changes can be made after is gone. In order to properly close it you will need the Dispose() or Close() method. In the other hand, if you use the Show() method and you close it, the form will be disposed and can not be modified after.
If you are displaying child form as a modal dialog box, you can set DialogResult property of child form with a value from the DialogResult enumeration which in turn hides the modal dialog box, and returns control to the calling form. At this time parent can access child form's data to get the info that it need.
For more info check this link:
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.dialogresult(v=vs.110).aspx
i had same problem i solved it like that , here are newbies step by step instruction
first create object of child form it top of your form class , then use that object for every operation of child form like showing child form and reading value from it.
example
namespace ParentChild
{
// Parent Form Class
public partial class ParentForm : Form
{
// Forms Objects
ChildForm child_obj = new ChildForm();
// Show Child Forrm
private void ShowChildForm_Click(object sender, EventArgs e)
{
child_obj.ShowDialog();
}
// Read Data from Child Form
private void ReadChildFormData_Click(object sender, EventArgs e)
{
int ChildData = child_obj.child_value; // it will have 12345
}
} // parent form class end point
// Child Form Class
public partial class ChildForm : Form
{
public int child_value = 0; // variable where we will store value to be read by parent form
// save something into child_value variable and close child form
private void SaveData_Click(object sender, EventArgs e)
{
child_value = 12345; // save 12345 value to variable
this.Close(); // close child form
}
} // child form class end point
} // name space end point
Many ways to skin the cat here and #Mitch's suggestion is a good way. If you want the client form to have more 'control', you may want to pass the instance of the parent to the child when created and then you can call any public parent method on the child.
I think the easiest way is to use the Tag property
in your FormOptions class set the Tag = value you need to pass
and after the ShowDialog method read it as
myvalue x=(myvalue)formoptions.Tag;
When you use the ShowDialog() or Show() method, and then close the form, the form object does not get completely destroyed (closing != destruction). It will remain alive, only it's in a "closed" state, and you can still do things to it.
The fastest and more flexible way to do that is passing the parent to the children from the constructor as below:
Declare a property in the parent form:
public string MyProperty {get; set;}
Declare a property from the parent in child form:
private ParentForm ParentProperty {get; set;}
Write the child's constructor like this:
public ChildForm(ParentForm parent){
ParentProperty= parent;
}
Change the value of the parent property everywhere in the child form:
ParentProperty.MyProperty = "New value";
It's done. the property MyProperty in the parent form is changed. With this solution, you can change multiple properties from the child form. So delicious, no?!
I have instantiated an object from another class in order to use properties from that class. Everything works fine within the button event, however, outside of the button event I get an error telling me my instantiated object is being used as a type. If I take this very same code and cut and paste it into the button event, I do not receive an error message. I do not understand what is happening and why. The object is instantiated whether it is inside or outside of the button event so why doesn't it work outside of the button event? I need those two label fields auto-filled from another form as soon as the form opens, not when the button is clicked.
Here is my code:
public partial class MeasurementsForm : Form
{
private MeasurementsBOL busObject = new MeasurementsBOL();
//autofill bodyfat and body weight from nutrition form when form opens
busObject.BodyFatB4 = double.Parse(lblBodyFatB4FromNutrition.Text);
busObject.BodyWeightB4 = double.Parse(lblWeightB4FromNutrition.Text);
//default constructor
public MeasurementsForm()
{
InitializeComponent();
busObject.InitializeConnection();
}
//event handler for B4 input data
private void btnEnterMeasurementsB4_Click(object sender, EventArgs e)
{
//convert input data and assign to variables
busObject.ChestMeasurementB4 = double.Parse(txtChestB4.Text);
busObject.WaistMeasurementB4 = double.Parse(txtWaistB4.Text);
busObject.HipsMeasurementB4 = double.Parse(txtHipsB4.Text);
busObject.RightThighB4 = double.Parse(txtRightThighB4.Text);
busObject.LeftThighB4 = double.Parse(txtLeftThighB4.Text);
busObject.RightArmB4 = double.Parse(txtRightArmB4.Text);
busObject.LeftArmB4 = double.Parse(txtLeftArmB4.Text);
//call method to save input data
busObject.SaveB4Data();
//clear text boxes of data
this.txtChestB4.Clear();
this.txtWaistB4.Clear();
this.txtHipsB4.Clear();
this.txtRightThighB4.Clear();
this.txtLeftThighB4.Clear();
this.txtRightArmB4.Clear();
this.txtLeftArmB4.Clear();
//close form
this.Close();
}
Here are my two properties from the MeasurementsBOL class. Although I don't show it, the object has been instantiated:
//properties for variables
public double BodyFatB4
{
get { return bodyFatB4; }
set { bodyFatB4 = nutritionObject.BodyFatStart;}
}
public double BodyWeightB4
{
get { return bodyWeightB4; }
set { bodyWeightB4 = nutritionObject.BodyWeight; }
}
This code isn't in any method, constructor etc:
private MeasurementsBOL busObject = new MeasurementsBOL();
//autofill bodyfat and body weight from nutrition form when form opens
busObject.BodyFatB4 = double.Parse(lblBodyFatB4FromNutrition.Text);
busObject.BodyWeightB4 = double.Parse(lblWeightB4FromNutrition.Text);
It's fine to have a variable declaration, but you can't just add extra statements like that. Fortunately, you can use an object initializer:
private MeasurementsBOL busObject = new MeasurementsBOL()
{
BodyFatB4 = double.Parse(lblBodyFatB4FromNutrition.Text),
BodyWeightB4 = double.Parse(lblWeightB4FromNutrition.Text)
};
Basically, a type can only contain members such as field declarations, constructor declarations, property declarations, method declarations etc. It can't contain just statements.