I have two Forms in my application. A Form has the following fields: txtPower, txtTension and txtCurrent. I would like to access the values filled in these TextBox through another Form. In the second Form I instantiated an object of the first Form (MotorForm), however I do not have access to the TextBox.
public MacroForm()
{
InitializeComponent();
MotorForm motorForm = new MotorForm();
motorForm.Show();
}
Is there any way?
Please do not expose the controls in your form. Never. (Unless you have a really good reason.)
If the problem is simple enough not to use MVVM (or the like) in your program (which you should consider for every program that's but trivial), you should expose the values of the instantiated form via properties. Think
public string Power
{
get { return txtPower.Text; }
set
{
if(ValidatePower(value))
{
txtPower.Text = value;
}
else
{
// throw ??
}
}
}
If we can make a sensible assumption about the type of the value we could extend this to
public double Power
{
get
{
// parse the value
// validate the value
// throw if not valid ??
// return the value
}
set
{
// validate the value
// set the value in the text box
}
}
If you exposed the txtPower object, you'd make the instantiating class depend on implementation details of the instantiated class, which is virtually never a good thing.
It seems that your problem is a perfect situation for using ShowDialog for opening your form.
To accomplish this, you need to change the Modifiers property of the controls you want to access on MotorForm and set them to Public. And also set the DialogResult property of your form somewhere to a desired value i.e OK. Anyway the easier way to do this is to set it on the button that is supposed to close the form. Suppose OK or CANCEL buttons.
Then you can create your form this way:
MotorForm motorForm = new MotorForm();
if(motorForm.ShowDialog() == DialogResult.OK)
{
string myValue = motorForm.txtPower.Text; //you can access your values this way
}
Related
I have a base form (BaseMDIForm) that several forms (Client, Inventory, Orders, etc) inherit from. On this base form is a protected string "windowID". This id gets set by each form as a way to uniquely identify the object currently open in that form (Client.ID, Inventory.ID, Order.ID, etc).
I am successfully using this method on the Client form to find a specific client id on any open Client form:
// method is in the Client form (and is coded to specifically look for Client forms)
private Boolean FindFormWithWindowID(string windowID)
{
foreach (Form form in this.MdiParent.MdiChildren)
{
if (form.GetType() == typeof(frmClient))
{
frmClient clientForm = (frmClient)form;
if (clientForm.windowID == windowID)
{
// close this form because the client is open on an existing form
if (this.windowID == "") // this won't be set yet if we're searching for an existing form
Close();
form.Activate();
return true;
}
}
}
}
The idea behind this concept is that when a user tries to open a client record (or inventory, order, etc) that is already open on an existing form, the existing form is given the focus and brought to the front (and what would have been the newly opened form is then closed).
I'm trying to move this method to the base form so this method doesn't need to be continually created in any inherited forms, just called from those forms, as in:
if (!FindFormWithWindowID(ClientForm, windowID))
{
// continue loading new form
}
Is there a way to pass in the form type (Client, Inventory, Orders, etc), then have this new base method loop through the existing MdiChildern of the specific passed-in form type to find a specific form that contains a given window id (keeping in mind that this method will be called from many different types of inherited forms)? I'm trying to avoid adding a switch statement to determine the form type, as this would force me to update it anytime a completely new form is added to the project.
WindowID doesn't actually exist on a form so I'm assuming your've got an inherited base form that you have added WindowID to.
public InheritedForm : Form
{
public string WindowID { get; set; }
}
If this is the case then you can replace your current FindFormWithWindowID method with:
string windowidtolookfor = "1234";
InheritedForm foundform = Application.OpenForms.OfType<InheritedForm>().Where(f => f.WindowID = windowidtolookfor).FirstOrDefault();
If you want a specific type of form:
MyForm foundform = Application.OpenForms.OfType<MyForm>().Where(f => f.WindowID = windowidtolookfor).FirstOrDefault();
You will need to check that foundform is not null before you attempt to do anthing with it as FirstOrDefault() will return null if it cannot return a matching item.
This can be called from anywhere so you don't need to worry about picking a sensible location for it.
There seems to be a little confusion about what this is doing so I'll break it down:
Application.OpenForms is a property that lists all the Forms that are open within the application.
We call this then we specify the type of Form we're looking for with `OfType() this filters down the OpenForms to only those with a typeof FormX.
After this we add Where(f => f.WindowID = "1234")
This tells the query that we want only those forms of FormX that have a WindowID of "1234".
Finally we add FirstOrDefault(), this will return the first instance it finds where the Form is FormX and WindowID = "1234". If no form exists that matches the criteria then it will return NULL.
It is functionally equivalent of your FindFormWithWindowID but it allows you to change it each time you use it by substituting the OfType with whatever form type you want.
If you only want a boolean result at the end then just do it like this:
if (Application.OpenForms.OfType<FormX>().Where(f => f.WindowID == windowidtolookfor).FirstOrDefault() != null)
{
// Found a window matching the criteria
}
else
{
// Not found a window matching the criteria.
}
For a fixed number of types, you could pass a string representing the type, and then check each windows type to see if it matches.
System.Type getTypeOfForm(string docType) {
switch (docType) {
case "Customer":
return typeof(MyNameSpace.CustomerMDIForm);
case "Invoice":
return typeof(MyNameSpace.InvoiceMDIForm);
case "Order":
return typeof(MyNameSpace.OrderMDIForm);
...
default:
throw new Exception("Unknown Form Type");
}
}
You can stitch the return type into your existing loop by plugging the returned runtime type in where you have '== typeof(frmClient)'. If you passed around the fully qualified class string for your target form type, you can also convert that into a System.Type object by using System.GetType(string).
You can also avoid any string to type mapping shenanigans if you simply pass a variable of System.Type to your search:
if (!FindFormWithWindowID(typeof(MyNameSpace.CustomerMDIForm), windowID))
Working on a project where I am storing my data using a GenericList, based off a class I created which contains a handful of string members. This works great, but things get troublesome when I try to pass this list to a second form. I initially setup a get/set block in the second form to accept the list and then return it, but the destination is always null. As a workaround I changed the local list on the second form to public and am able to access it that way, but then instead of getting a copy of the list, I get ByRef passing so any changes made are reflected in the master list. Since I want to be able to not accept these changes, I really want this to be a pass by value. These two problems have to be linked...
Here is the setup. In form1 I have this definition at the class level, making this somewhat of a global variable (yeah its bad, but it works for me):
private List<ServerList> theServerList = new List<ServerList>();
Later on I create the new form and (try to) pass my data into it using:
frmEditor theEditor = new frmEditor();
theEditor.updatedServerList = theServerList;
DialogResult res = theEditor.ShowDialog();
On the second from, I have this to receive the data:
private List<ServerList> myServerList = new List<ServerList>();
public List<ServerList> updatedServerList
{
get { return myServerList; }
set { myServerList = updatedServerList; }
}
This results a list on form2 (the myServerList) always being empty. Since this was not working, I commented out all these lines and changed the myServerList definition on form2 to public. Now after instantiating form2 I am able to get the data over by doing this:
theEditor.myServerList = theServerList;
This works in that the data nicely shows up form2, but this kind of an assignment just copies the pointer of the data block in memory from one variable to the other (basically a ByRef passing), so any changes I make on form2 change "both" lists since they are the same. I would like to have a local copy in form2 so I can make changes and then accept them or not depending of if the user clicks Cancel (drop all changes), or OK (copy the local data from form2 back to form1).
Your original does not work because your setter should be:
public List<ServerList> updatedServerList
{
get { return myServerList; }
set { myServerList = value; }
}
If you want to copy the list, you can use ToList on the incoming value:
public List<ServerList> updatedServerList
{
get { return myServerList; }
set { myServerList = value.ToList(); }
}
This is not to do with 'by value' vs 'by reference' since List<T> is a reference type, so the value of a variable of type List<ServerList> is a reference which is copied into the setter method. This reference will point to the same object in both the caller and receiver classes. If you want to copy the contents of the list you need to do it manually using ToList or similar.
I am creating several .NET User Controls and I am trying to figure out the best way to go about setting properties. I have an address control and I am trying to create a property called ShowCountry which will either hide or show the control's country ddl.
I have been trying to set most of my properties similar to the below code:
public bool ShowCountry
{
get { return (bool)ViewState["ShowCountry"]; }
set
{
ViewState["ShowCountry"] = value;
pnlCountry.Visible = value;
}
}
How would I set a default value for this property? When I run my page with the control on it, it instantly errors out in the "get{}" when ShowCountry is used in one of my functions because I never set ShowCountry="false" in the control's tag. If I set this property when declaring the control everything works fine.
Also is what I am doing with the ViewState a good way to keep property values across postbacks?
Could someone show me how they would write this property?
The specs are:
Must keep value across postbacks, Must default to false
you can try this in order to avoiding error..
public bool ShowCountry
{
get {
if(ViewState["ShowCountry"] != null ){
return (bool)ViewState["ShowCountry"];
}
else {
//return the default value
return false;
}
}
set
{
ViewState["ShowCountry"] = value;
pnlCountry.Visible = value;
}
}
i think view state is best approach alternatively you can use hidden field in order to save value against post back.
I have a C# Form that prints multiple instances of a User Control. Let's say that the form prints 5 instances of the User Control (Please see the link attached). How can I store/save the data inputted in all User Controls? Thanks
Here is the screenshot of the C# Form:
You'll have to store the User Controls when you instantiate them in a List or something.
You could have a class like this:
class SomeUC : UserControl
{
public SomeUC()
{
}
// A public method.
public string GetData()
{
return textBox1.Text;
}
}
Where textBox1 is the Name of a TextBox in your SomeUC
And then inside your main or something.
// Instantiate a List that will hold your UserControls, this has to be outside all methods
List<SomeUC> list = new List<SomeUC>();
// And now when you want to build your UCs
// Instantiate your UserControl
SomeUC uc1 = new SomeUC();
// Store your UserControl in a List or something (Can't help you with that)
list.Add(uc1);
Add as much as you want.
A List is not the only way you can do that, but since you don't know how many UserControls you're going to build beforehand, it makes since to use a List.
And then you can access them from the list by their index.
SomeUC uc1 = list[0];
string data = uc1.GetData();
This is an example of accessing one control (the TextBox) in your SomeUC. For other classes (such as the ComboBox) the interaction is different. Meaning you won't have a Text property in the ComboBox. You'll have to figure out things like that on youself. A little research is what it takes. You can always come back if you couldn't find a solution for something.
You can create a property like this for each item in user control.
public string DG
{
get
{
return txtDG.Text;
}
set
{
txtDG.Text = value;
}
}
Then you can access the control value by using following line in your form.
supposed you have created a usercontrol MyControl and you have placed some object of this control in FlowLayoutPenal (pnlFLP).
To get value from control
string DG = ((MyControl)pnlFLP.Controls[0]).DG;
To set value in control
((MyControl)pnlFLP.Controls[0]).DG = "1";
Try this code for accessing user control in the page
Dim txtName As TextBox = TryCast(UserControlName.FindControl("txtName"), TextBox)
I'm new in C# but not new to coding --being doing it for almost two decades--, and have a problem with properties in a custom control I'm building, which inherits from a Panel. When I put my properties, I can see them in the Designer properties list and can even set them, but when running my little application, it seems these properties values are not used. The same if I change a property programatically: no error but my control does nothing, it is like they are not properly set. However, if I do it programatically whithin the class, they do work. My guess is that something in my properties set/get stuff is not right. Please see the following code chunk of how I'm doing it:
public class ColorStrip : Panel
{
// properties
// ------------------------------------------
// size of color clusters (boxes)
private int _clusterSize = 20;
// controls if show the buttons panel
private Boolean _showButtons;
// property setters/getters
// ------------------------------------------
// clusterSize...
public int clusterSize
{
get { return _clusterSize; }
set { _clusterSize = value; }
}
// showButtons...
public Boolean showButtons
{
get { return _showButtons; }
set { Console.Write(_showButtons); _showButtons = value; }
}
....
So in my form, for instance in the load or even in a click event somewhere, if I put colorStrip1.showButtons = false; or colorStrip1.showButtons = true; whatever (colorStrip1 would be the instance name after placing the control in the form in design mode)... console.write says always 'false'; Even if I set it in the design properties list as 'true' it will not reflect the settled value, even if I default it to true, it will never change externally. Any ideas? Non of the methods get the new and externally settled property value neither, obviously the getter/setter thing is not working. Seems to me I'm not doing right the way I set or get my properties outside the class. It works only inside it, as a charm...Any help...very appreciate!
Cheers
lithium
p.s. TO CLARIFY SOLUTION:
Setting the property in this case didn't work because I was trying to use a new set value within the constructor, which seems can't get the new values since it is, well, building the thing. If I change the property value in Design mode > Property editor or in code externally to the object, say in it's parent form's load event, it will change it but readable for all methods except the constructor, of course :)
It's likely an issue of the order of execution. Your property setter just sets a variable, but doesn't actually trigger anything on the control to update the state related to this variable (e.g. adding or showing the buttons I assume).
When you set the property befre the rest of the initialization is done, the value is being used, otherwise it isn't because during the initial go the default value is still the property value.
You need to act on the setter, here's some pseudocode to illustrate:
set {
_showButtons = value;
if (alreadyInitialized) {
UpdateButtons();
}
}
Note: make sure to first set the value, then act - otherwise you end up using the old value (just like your Console.Write() is doing).
The quoted code doesn't look problematic. Are you sure you're referencing the same instance of ColorStrip? Also, check your .Designer.cs file to ensure that the code setting the property is there.
In fact, try simplifying your code by using auto-implementing properties:
public int clusterSize { get;set;}
public Boolean showButtons {get;set;}
public ColorStrip() { ... clusterSize = 20; ... }