My problem is I have a variable that I need the window to send back, so I am using out to accomplish this. Here is an example of the constructor for the WPF window.
public CustomYesNo(out bool FormFilled)
{
InitializeComponent();
FormFilled = false;
}
The problem i'm having is I want it so one of the other methods in the class will be able to modify the FormFilled variable that gets sent back to the calling class like below.
private void Button_Yes_Click(object sender, RoutedEventArgs e)
{
FormFilled = true;
Close();
}
Obviously the Button_Yes_Click method does not have access to the FormFilled variable, and I am trying to figure out how I could possible change the value of the FormFilled variable from this method since this variable is only in the constructor's scope. Is what I am trying to do possible using 'out' or do I need to go another route?
Try this pattern
Calling Method:
class foo
{
public void bar()
{
DialogForm myDialogForm = new DialogForm();
myDialogForm.ShowDialog();
if (myDialogForm.DialogResult)
{
//Its true
}
}
}
Form window:
public partial class DialogForm : Window
{
public DialogForm()
{
InitializeComponent();
}
void submitButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
}
The calling method in WPF is slightly different for checking the result:
bool? result = myDialogForm.ShowDialog();
if (result.HasValue && result.Value)
Related
I'm having trouble assigning the value of a variable from one class to another class. I have tried to do it in several ways but none works, the variable still has no value inside my method.
First Class:
namespace Simulador
{
public partial class Cidade : Window
{
private int QNTTodinho;
private void todinhobotao_Click(object sender, RoutedEventArgs e)
{
TodinhoBotaoo();
}
public void TodinhoBotaoo()
{
QNTTodinho += 1;
MainWindow Valor = new MainWindow(QNTTodinho);
}
}
}
Second Class:
namespace Simulador
{
public partial class MainWindow : Window
{
private int QNTTodinho;
public MainWindow(int qNTTodinho)
{
QNTTodinho = Convert.ToInt32(qNTTodinho);
}
private void Salgadinho_Click(object sender, RoutedEventArgs e)
{
Dinheiro22.Content = QNTTodinho.ToString();
}
}
}
I am guessing that the startup form for your application is
MainWindow. Which means you are creating an instance of MainWindow and running it as the main application window.
If this is the case, then creating another instance of MainWindow like what you are doing and passing the integer to it in the constructor wouldn't affect the actual main window. It is just setting the value in a copy of the MainWindow and directly scrapping that copy afterwards.
One way to fix that, although not the best practice, is to change the member you want to modify to be a static member, like that:
public partial class MainWindow : Window
{
public static int QntTodinho { get; set; }
public MainWindow()
{
}
private void Salgadinho_Click(object sender, RoutedEventArgs e)
{
Dinheiro22.Content = this.QntTodinho.ToString();
}
}
public partial class Cidade : Window
{
private int qntTodinho = 0;
private void todinhobotao_Click(object sender, RoutedEventArgs e)
{
TodinhoBotaoo();
}
public void TodinhoBotaoo()
{
this.qntTodinho += 1;
MainWindow.QntTodinho = this.qntTodinho;
}
}
Notice as well that I've done the following changes:
Used pascalCasing for private member
Used CamelCasing for public member
Get rid of Convert.ToInt32 as it is not needed
Things to consider with this solution are mainly thread safety and the lack of ways to notify MainWindow when the value changes.
I have a method, where I call a new Windows Form in Class A. And in the new Form, I use a Dropdown menu and store the selected Item from the Dropdown in a variable, called selectedItem.Now I have to access this selectedItem in Class A. I use the following code.
public class A
{
public method callingmethod()
{
ExceptionForm expform = new ExceptionForm();
expform.Show();
string newexp = expobj.selectedexception;
}
}
And my code in New Form,
public partial class ExceptionForm : Form
{
public string selectedexception = string.Empty;
private void btnExpSubmit_Click(object sender, EventArgs e)
{
selectedexception = this.comboBox1.GetItemText(this.comboBox1.SelectedItem);
this.Close();
return;
}
}
Now After clicking on Submit button, I get the correct value in selectedItem, But I could not pass it to Class A. How to retun to Class A?
If you are ok with posting ExceptionForm over parent form by disabling it, go for ShowDialog. But, if you do not wish to disable parent for and continue popping ExceptionForm as a new and independent window, try eventing back to parent form. Here I show an example on how to do so:
public partial class ExceptionForm : Form
{
public delegate void SelectValueDelegate(string option);
public event SelectValueDelegate ValueSelected;
private void btnExpSubmit_Click(object sender, EventArgs e)
{
this.Close();
if (this.ValueSelected!= null)
{
this.ValueSelected(this.comboBox1.GetItemText(this.comboBox1.SelectedItem));
}
return;
}
}
And in calling class:
public class A
{
public method callingmethod()
{
ExceptionForm expform = new ExceptionForm();
expform.ValueSelected += ExceptionForm_ValueSelected;
expform.Show();
}
private void ExceptionForm_ValueSelected(string option)
{
string newexp = option;
// Do whatever you wanted to do next!
}
}
Use ShowDialog() method.
expform.ShowDialog();
string newexp = expobj.selectedexception;
I've found some good posts about using methods in other forms and tried to implement them in my code, but I'm getting a null object error (specifically, the frmAddMaterials object is null). Code compiles fine, error occurs when trying to use the create materials button on the second form.
My first form has an array to hold material information. When the user clicks a link on this first form, they are prompted with a second form where they can enter custom material information in the event that the material they are interested in using is not on designed in. Upon clicking "Add material" on form 2, I would like the RefreshMaterials() method on the first form to run, which creates a new entry in the array based on information from the second form.
Form1:
public partial class frmSnapFitMain : Form
{
public frmMat frmAddMaterials;
public Materials[] material = new Materials[20];
Image[] problemtype = new Image[7];
private void linkLabel1_LinkClicked_1(object sender,LinkLabelLinkClickedEventArgs e)
{
frmMat frmAddMaterials = new frmMat(this);
frmAddMaterials.Show();
}
public void RefreshMaterials()
{
material[Materials.MaterialCount] = new Materials(frmAddMaterials.txtName.Text, Double.Parse(frmAddMaterials.txtFlex.Text), Double.Parse(frmAddMaterials.txtFriction.Text), Double.Parse(frmAddMaterials.txtStrain.Text)); //little m, materials here is for specific instance
cboxMatSelect.Items.Add(frmAddMaterials.txtName.Text);
frmAddMaterials.txtName.Text = ""; //reset fields
frmAddMaterials.txtFlex.Text = "";
frmAddMaterials.txtFriction.Text = "";
frmAddMaterials.txtStrain.Text = "";
}
}
Form 2:
public partial class frmMat : Form
{
private readonly frmSnapFitMain _form1;
public frmMat(frmSnapFitMain Form1)
{
InitializeComponent();
this._form1 = Form1;
}
public void btnCreate_Click(object sender, EventArgs e)
{
this._form1.RefreshMaterials();
this.Close();
}
public void frmMat_Load(object sender, EventArgs e)
{
}
}
In the linkLabel1_LinkClicked_1 method you declare a new instance of frmMat. This instance happens to have the same name of the global variable but it is a local one that disappears when you exit from the method.
private void linkLabel1_LinkClicked_1(object sender,LinkLabelLinkClickedEventArgs e)
{
// This is not the global variable frmAddMaterials.
// It is a local one to this method
frmMat frmAddMaterials = new frmMat(this);
frmAddMaterials.Show();
}
Of course this means that in your RefreshMaterials you use the global variable that has never been initialized
You just need to remove the declaration of a local variable and initialize the global one
private void linkLabel1_LinkClicked_1(object sender,LinkLabelLinkClickedEventArgs e)
{
// This initializes the global variable
frmAddMaterials = new frmMat(this);
frmAddMaterials.Show();
}
Said that it is always a good practice to use a 'defensive programming attitude' when using global variables and test if the variable has been correctly initialized.
public void RefreshMaterials()
{
if(frmAddMaterials != null)
{
material[Materials.MaterialCount] = new Materials(.....)
cboxMatSelect.Items.Add(frmAddMaterials.txtName.Text);
frmAddMaterials.txtName.Text = ""; //reset fields
frmAddMaterials.txtFlex.Text = "";
frmAddMaterials.txtFriction.Text = "";
frmAddMaterials.txtStrain.Text = "";
}
}
I also suggest to subscribe to the FormClosing event of frmAddMaterials to set your instance to null when the form closes
private void linkLabel1_LinkClicked_1(object sender,LinkLabelLinkClickedEventArgs e)
{
if(frmAddMaterials != null)
{
frmAddMaterials = new frmMat(this);
frmAddMaterials.Show();
frmAddMaterials.FormClosing += frmMaterialsClosing;
}
}
private void frmMaterialsClosing(object sender, CancelEventArgs e)
{
frmAddMaterials = null;
}
This allows you to restart the 'cycle' because when you click again the linklabel your global variable is null and you could reinitialize it to the new instance created in the linklabel click event handler.
I've got code and i know I'm 99% of the way there. C# coding in MS VS2008.
Basically I have a form that has 4 radio buttons and a Continue button. the user clicks one of the radio buttons and clicks continue, and this all works fine.
However, I want to use the value entered by the user (i.e. if they click the first button, I want a variable equal to 1, 2nd button equals 2 and so on). I tried doing this in various points but the only place I can get it to run is in the private void btnOkClick line, which means I can use the values outside this void, which is what I really want.
I've tried playing around with setting some enums and such (commented out in the code below), but I can't quite get it. I know I must be close but my novice-ness is truly showing as I keep reading posts and can't quite grasp it.
In short, I want to be able to have other classes in my VS2008 project be able to reference whatever value the user selected in the initial form.
namespace AmortClient
{
public partial class frmLoadACTFCST : Form
{
public frmLoadACTFCST()
{
InitializeComponent();
//set the parent of the form to the container
//this.MdiParent = parent;
}
//public enum ACTFCST
//{
// ACT = 1,
// FCST = 2,
// PLAN = 3,
// FiveYearPlan2012=4
//}
//private ACTFCST _actfcst = ACTFCST.ACT;
//public ACTFCST actfcst
//{
// get { return _actfcst; }
// set { _actfcst = value; }
//}
private void frmLoadACTFCST_Load(object sender, EventArgs e)
{
}
private void groupBox1_Enter(object sender, EventArgs e)
{
}
private void btnActual_CheckedChanged(object sender, EventArgs e)
{
}
private void btnForecast_CheckedChanged(object sender, EventArgs e)
{
}
private void btnPlan_CheckedChanged(object sender, EventArgs e)
{
}
private void btn5YrPlan2012_CheckedChanged(object sender, EventArgs e)
{
}
private void btnContinue_Click(object sender, EventArgs e)
{
string ACTFCSTtext = "";
int dataTypeKey = 0;
if (btnActual.Checked)
{
ACTFCSTtext = btnActual.Text;
dataTypeKey = 1;
}
else if (btnForecast.Checked)
{
ACTFCSTtext = btnForecast.Text;
dataTypeKey = 2;
}
else if (btnPlan.Checked)
{
ACTFCSTtext = btnPlan.Text;
dataTypeKey = 3;
}
else if (btn5YrPlan2012.Checked)
{
ACTFCSTtext = btn5YrPlan2012.Text;
dataTypeKey = 4;
}
string msg = "";
msg = ACTFCSTtext + " " + dataTypeKey;
//btn5YrPlan2012
MessageBox.Show(msg);
Close();
}
}
}
Your dataTypeKey and ACTFCSTtext variables need to be declared as instance variables for your Form object if you want to access them from any other methods within your form. If you want to use them with some other form, you can pass them either as constructor arguments, or set some properties of said other form.
So you'd declare them just after the class declaration if you want them to be instance variables. They should still be private, meaning they can only be accessed from within your frmLoadACTFCST class.
public partial class frmLoadACTFCST : Form
{
private string ACTFCSTtext = "";
private int dataTypeKey = 0;
...
EDIT: if you want to access variables from one object in a different object (or static class), your options are as follows...
1) Declare your variables as public instance variables (same as shown above but public; these are known as Properties when you give them getter and setter methods). Your class that needs access to these variables would need to have a reference to the class that owns the variables.
Example:
FormA has a public property named SomeString.
FormB needs to access SomeString.
FormB needs a reference to FormA, and would access the variable as...
formAReference.SomeString
2) Pass the values of the variables as arguments to some method for the class that needs access.
Example:
FormA has a private instance variable named SomeString.
FormB needs access to SomeString.
If FormA instantiates FormB, it can pass the value of SomeString to FormB's constructor...
//From within FormA's code
FormB formB = new FormB(SomeString);
//FormB's constructor
public FormB(string someString)
{
this.someString = someString;
}
Maybe there is a smarter way to do it.
public partial class frmLoadACTFCST : Form
{
public frmLoadACTFCST()
{
InitializeComponent();
actfcst = ACTFCST.ACT;
btnActual.Tag = ACTFCST.ACT;
btnActual.Checked = true;
btnForecast.Tag = ACTFCST.FCST;
btnPlan.Tag = ACTFSCT.PLAN;
btn5YrPlan2012.Tag = ACTFCST.FiveYearPlan2012;
}
public enum ACTFCST
{
ACT = 1,
FCST = 2,
PLAN = 3,
FiveYearPlan2012=4
}
public static ACTFCST actfcst { get; private set; }
private void CheckedChanged(object sender, EventArgs e)
{
// All the buttons uses this Click-event.
actfcst = (sender as Button).Tag as ACTFCST;
}
private void btnContinue_Click(object sender, EventArgs e)
{
MessageBox.Show(actfcst.ToString());
Close();
}
}
The point is that all the buttons calls CheckedChanged when clicked.
Using a static means that others can access the value using something like this:
frmLoadACTFCST.ACTFCST value = frmLoadACTFCST.actfcst;
// Do something based on value.
I hope this helps you in yoyr quest.
If you select a control in design view, the properties window contains an item named "Modifiers". You can make the control public here.
A better way would be to create a new public property on your form that yields the value of the currently selected radio button.
I always set the modifiers on my form to private,I don't like internal nor public.
Till now I used to Invoke like this:
public string Addtext
{
if(InvokeRequired)
{
Invoke((MethodInvoker)delegate
{
textbox.text = value;
});
}
else
textbox.text = value;
}
But adding such property for every member on my form is just not Object Orientated at all.
I want to create a function that will Invoke the parameter(action).I tried my best,but I failed - it requires the form members to be public or internal :(
public void PerformActionOnForm(Action<FormMain> action)
{
var form = Form.ActiveForm as FormMain;
object s = action.Clone();
if (form != null)
{
form.PerformAction(action);
}
}
public void PerformAction(Action<FormMain> action)
{
if (InvokeRequired)
Invoke(action, this);
else
action(this);
}
two problems in my code:
It requires the property I'd like to change to be != private :(
Doesn't work if the form is not on focus.
In what way is adding properties for data that needs to be accessed or set outside of the scope of the form "not object oriented at all?" This is really your only option. Code in an anonymous delegate (or any delegate, for that matter) executes in the context in which it was declared. The only facility for getting around visibility issues is reflection, and that is big smelly code smell. Create your properties and use them as appropriate.
As for your second option, I'm assuming that you want to execute this on your "main form". You have two options here: assume that there is only one instance and keep that as a static property on the class, assigning it in the instance constructor.
public partial class MainForm : Form
{
private static MainForm singletonInstance;
public static MainForm SingletonInstance
{
get { return singletonInstance; }
}
public MainForm() : base()
{
InitializeComponent();
singletonInstance = this;
}
}
public void PerformActionOnForm(Action<FormMain> action)
{
var form = MainForm.SingletonInstance;
// object s = action.Clone(); What was this for?
if (form != null)
{
form.PerformAction(action);
}
}
The other only works if all of your forms are properly "owned" and the only form with no owner is your main form. In that instance you could do this:
public void PerformActionOnForm(Action<FormMain> action)
{
var form = Form.ActiveForm.TopLevelControl as FormMain;
// object s = action.Clone(); What was this for?
if (form != null)
{
form.PerformAction(action);
}
}
Calling a UI component from a non-UI thread
Assuming you only have one message loop (99% that's the case), then:
public static class SynchronizedInvoker
{
public static void Invoke(Action action)
{
Form form = Application.OpenForms.Cast<Form>().FirstOrDefault();
if (form != null && form.InvokeRequired)
form.Invoke(action);
else
action();
}
}
Calling the code:
SynchronizedInvoker.Invoke(() => myForm.Text = myText);
Accessing private UI components
Accessing private UI members is not different from accessing other private members to .NET objects. It's in the nature of a private member not to be accessed from other objects. If you still want access, you'll eitherway have to pass the reference of the UI component to the caller or use reflection to resolve the path to the private object.
An example of passing the reference of the UI component to the caller:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(delegate { MyWorker.Run(button1); });
}
}
class MyWorker
{
public static void Run(Button button)
{
SynchronizedInvoker.Invoke(() => button.Text = "running");
Thread.Sleep(5000); // do some important work here
SynchronizedInvoker.Invoke(() => button.Text = "finished");
}
}
Using reflection is technically possible, but not ideal. You need to know the path to the private member, and that requires information about the internals of an object. You should then question yourself why you've made it private in the first place.
Why do you have so many possible entry points to your form that could be called from other threads? Do the thread marshaling lower down (a controller for your form might help) and you won't have to worry about boilerplate code like this.