Passing values between forms using a public textbox - c#

RESOLVED: Turned out to be a visual studio problem. Closed visual studio, cleaned and rebuilt, and the value started showing. Thanks all for the help, sounds like I need to switch to VS2010.
This may not be the best, safest, or preferred way to pass values between forms, but this is the way I am attempting for the moment. So, please do help me to get this way working. After you provide an answer, you're more than welcome to add in some better ways of doing this.
The problem is, when the modal dialog box closes and I go back to the owner, the textbox value from the modal is an empty string rather than the actual value. I've read in several places this should not be the case, as the data should persist even after the modal box disposes. Here's my code.
public partial class PreferencesForm : Form
{
public PreferencesForm()
{
InitializeComponent();
}
private void okButton_Click(object sender, EventArgs e)
{
if (masterRadioButton.Checked == true)
{
if (password1TextBox.Text != password2TextBox.Text)
{
errorLabel.Text = "Passwords do not match, please re-enter both passwords and try again.";
this.Refresh();
}
else if (password1TextBox.Text == "" && password2TextBox.Text == "")
{
errorLabel.Text = "You must enter a password.";
}
else
{
okResultButton_Click(null, null);
}
}
else if (singleRadioButton.Checked == true)
{
okResultButton_Click(null, null);
}
}
private void cancelButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Dispose();
}
private void okResultButton_Click(object sender, EventArgs e)
{
// invisible button
this.DialogResult = DialogResult.OK;
this.Dispose();
}
And here is the code that calls the above form as a modal dialog box.
private void setPreferencesToolStripMenuItem_Click(object sender, EventArgs e)
{
PreferencesForm pf = new PreferencesForm();
DialogResult result = pf.ShowDialog();
if (result == DialogResult.OK)
{
if (pf.password1TextBox.Text != "")
{
masterPassword = pf.password1TextBox.Text;
}
else
{
masterPassword = null;
}
}
}
Thanks for any assistance. I'm getting pretty frustrated over here. >:(
Note: The ReadOnly property of the password1TextBox variable is correctly shown as true or false, depending on what I select in the modal form, but the text property will still not correctly display.

I'm guessing that Dispose will also dispose the controls it contains. After the controls have been disposed, the text is likely no longer valid either. Try Close rather than Dispose and then Dispose in the caller.

You should listen to the people answering your question. Dispose is supposed to clear out memory allocated, it doesn't matter if you can still get the ReadOnly property.
Don't call Dispose in the form, call dispose from the calling code, as in the example code from the ShowDialog method documentation (http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx#Y851). Note that Dispose is called just before the testDialog variable goes out of scope.
public void ShowMyDialogBox()
{
Form2 testDialog = new Form2();
// Show testDialog as a modal dialog and determine if DialogResult = OK.
if (testDialog.ShowDialog(this) == DialogResult.OK)
{
// Read the contents of testDialog's TextBox.
this.txtResult.Text = testDialog.TextBox1.Text;
}
else
{
this.txtResult.Text = "Cancelled";
}
testDialog.Dispose();
}

I propose just save the string of the control of your Dialog into string property, and retrieve value of that class property and not control's property value after Dialog is closed, and stop worrying about Dispose or not Dispose, or whatever else.
Hope this helps

Related

Cannot access a disposed object C# (showdialog dispose)

I am new to c# and kind of winging it. using Microsoft Visual C# 2010
I have checked many similar posts and none of the suggestions seem to help
I am getting the following error: "Cannot access a disposed object"
which references the main form here
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
RunPackages rp = new RunPackages();
this.Hide();
rp.ShowDialog();//The error points to this line
this.Show();
}
here is the code that blows up when the security check fails.
private void securityCheck()
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
InitializeComponent();
}
else
{
//this.BeginInvoke(new MethodInvoker(this.Close));
//this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
MessageBox.Show("You do not have permission to access this form!");
//this.Close();
this.Dispose();
}
}
EDIT
It looks like I am going to go with Adriano Repetti's idea of putting the security where I call the page, but I am a little nervous now having any security on the page.
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
RunPackages rp = new RunPackages();
this.Hide();
rp.ShowDialog();
this.Show();
}
else
{
MessageBox.Show("Not for You!");
}
}
private void btn_ListUpdater_Click(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("MDM") == 1)
{
ListUpdater lu = new ListUpdater();
this.Hide();
lu.ShowDialog();
this.Show();
}
else
{
MessageBox.Show("Private!");
}
}
EDIT2
Came up with the following possible solution but am nervous to use it because I am new at this and don't know what issues there might be. Any problems with just creating an event handler for form load?
namespace RunPackages
{
public partial class ListUpdater : Form
{
public ListUpdater()
{
InitializeComponent();
this.Load += new EventHandler(securityCheck);
}
private void securityCheck(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("MDM1") == 0)
{
MessageBox.Show("Not Allowed!");
this.Close();
}
}
You can't dispose of the form within the form itself. The ShowDialog() method tries to access the form on exit for things such as DialogResult.
After a form has been disposed almost all of its methods can't be accessed (and most of its properties are invalid).
In your first line of btn_RunPkgs_Click() you create an object and you dispose it inside its constructor. Per se, even if pretty bad habit you may even call Dispose() from within constructor, it may even work but then you try to use such object ShowDialog() will generate ObjectDisposedException. Note that this code will also lead to same result (an exception):
RunPackages rp = new RunPackages();
rp.Dispose();
Yes you may check IsDisposed but that won't make code readable and problem (IMO) is you're mixing things. Constructor shouldn't contain such logic.
The point isn't just where you dispose your form. What's better is to don't even create such form (let me assume, because you call InitializeComponent(), that securityCheck() is called inside form constructor), for this you may use a factory static method:
public static bool TryShowDialog(Form currentForm)
{
if (MyGlobals.FormCheck("RUN_JOBS") != 1)
return false;
if (currentForm != null)
currentForm.Hide();
RunPackages dlg = new RunPackages();
dlg.ShowDialog();
if (currentForm != null)
currentForm.Show();
return true;
}
Your calling function will then be reduced to:
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
RunPackages.TryShowDialog(this);
}
Note that such function is highly eligible for some refactoring (for example to extract code to hide/show existing form). Something like this:
public static bool ShowDialog<T>(Form currentForm, string authorizationId)
where T : Form, new()
{
if (MyGlobals.FormCheck(authorizationId) != 1)
return false;
if (currentForm != null)
currentForm.Hide();
T dlg = new T();
T.ShowDialog();
if (currentForm != null)
currentForm.Show();
return true;
}
Used like this (now code is reused everywhere):
SecurityHelpers.ShowDialog<RunPackages>(this, "RUN_JOBS");
Please note that calling code may be simplified (authorizationId may be an attribute on RunPackages, for example, and also currentForm can be deduced from current active form).
EDIT Calling Close() isn't better, if window handle has not been created (let's simplify little bit: it's created when window is shown) internally it'll call Dispose() (then above applies).
I would not try to disrupt the chaining of events that lead to the form creation.
The side effects are difficult to predict and what works today could not work in future versions.
Instead I would try a different approach
private void securityCheck()
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
InitializeComponent();
}
else
{
Label message = new Label();
message.Dock = DockStile.Fill;
message.Text("You do not have permission to access this form!.");
message.TextAlign = ContentAlignment.MiddleCenter;
this.Controls.Add(message);
}
}
In this way I let the form show with just one label that covers the entire form surface with your message. The user could only close the form (provided that you have not removed the Control Box)
By the way, this has the advantage of avoiding dangerous oversights because it doesn't require any change on the calling code and the final effect is to effectively block the use of the form.
If you insist in closing the form during its constructor phase then you could get some advices from this question
I came up with the following, can anyone tell me if there are any issues with this?
namespace RunPackages
{
public partial class ListUpdater : Form
{
public ListUpdater()
{
InitializeComponent();
this.Load += new EventHandler(securityCheck);
}
private void securityCheck(object sender, EventArgs e)
{
if (MyGlobals.FormCheck("MDM1") == 0)
{
MessageBox.Show("Not allowed!");
this.Close();
}
}
etc...
Use a flag. For example change the code, like this:
public bool IsDisposed;
private void securityCheck()
{
if (MyGlobals.FormCheck("RUN_JOBS") == 1)
{
InitializeComponent();
}
else
{
//this.BeginInvoke(new MethodInvoker(this.Close));
//this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
MessageBox.Show("You do not have permission to access this form!");
//this.Close();
this.Dispose();
this.IsDisposed = true;
}
}
Then:
private void btn_RunPkgs_Click(object sender, EventArgs e)
{
RunPackages rp = new RunPackages();
if(rp.IsDisposed)
return;
this.Hide();
rp.ShowDialog();//The error points to this line
this.Show();
}

Custom message box class has terminal "pop up" when the form does

Alright, this is a little strange, but essentially I needed a message box class with buttons that did not come as options within the message box class in c#. Therefore, I read up on how to create my own class (here is the link if your interested: http://social.msdn.microsoft.com/Forums/vstudio/en-US/1086b27f-683c-457a-b00e-b80b48d69ef5/custom-buttons-in-messagebox?forum=csharpgeneral), and used an example provided inside of that. Here is the relevant code:
public partial class Form1 : Form
{
public static bool MessageSucceded { get; set; }
public static string MessageContent{ private get; set; }
private void buttonMyMessageBox_Click(object sender, EventArgs e)
{
using (MyMessageForm myForm = new MyMessageForm())
{
myForm.ShowDialog();
if (MessageSucceded = myForm.ShowDialog(this) == DialogResult.OK)
{
if (MessageContent== "Yes do it")
{
//HERE DO WHAT YOU WANT IF THE USER CLICKS ON BUTTON YES DO IT
}
else if (MessageContent== "No, don`t do it")
{
//HERE DO WHAT YOU WANT IF THE USER CLICKS ON BUTTON NO, DON`T DO IT
}
}
}
}
}
public partial class MyMessageForm : Form
{
private void MyMessageForm_Load(object sender, EventArgs e)
{
this.StartPosition = FormStartPosition.CenterScreen;
this.ShowIcon = false;
this.ShowInTaskbar = false;
this.MinimizeBox = false;
this.MaximizeBox = false;
this.buttonYes.Text = "Yes do it";
this.buttonNo.Text = "No, don`t do it";
this.labelMyForm.Text = "Are you sure you want to… ?";
}
private void buttonYes_Click(object sender, EventArgs e)
{
Form1.MessageSucceded = true;
Form1.MessageContent= buttonYes.Text;
this.DialogResult = DialogResult.OK;
this.Close();
}
private void buttonNo_Click(object sender, EventArgs e)
{
Form1.MessageSucceded = true;
Form1.MessageContent= buttonNo.Text;
this.DialogResult = DialogResult.OK;
this.Close();
}
}
This works exactly as I intended it to, except for one small detail. Just before the message box pops up, for a split second, a terminal version of the message box form opens up, before it closes on its own and the windows form version opens and functions as expected. I can't understand why this is happening, and it isn't causing any performance issues that I can notice, but aesthetically it looks very bad. Does anyone know why this is happening or how to stop it? I'm using Visual Studio 2010 Express for what its worth. Thanks for any help you have and taking the time to read this.
Edit: heres my code for main:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
You're invoking ShowDialog() twice:
myForm.ShowDialog();
if (MessageSucceded = myForm.ShowDialog(this) == DialogResult.OK) {
Form has been closed so it'll close immediatly, right way to do it is to save its first result and check that in your if condition:
var result = myForm.ShowDialog();
if (MessageSucceded = (result == DialogResult.OK)) {
Or directly:
MessageSucceded = myForm.ShowDialog() == DialogResult.OK;
if (MessageSucceded) {
Moreover if you returns different results according to clicked button then you do not need to compare MessageContent (it's also a bad idea to have a reference to caller just to return a result):
private void buttonYes_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Yes;
this.Close();
}
private void buttonNo_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.No;
this.Close();
}
Note that now you can simply remove such code and add proper DialogResult property to each button (because assign Form.DialogResult and call Form.Close() is default behavior if Button.DialogResult property is assigned). Done that you can simply use it like this:
switch (myForm.ShowDialog())
{
case DialogResult.Yes:
break;
case DialogResult.No:
case DialogResult.Cancel: // Unless ControlBox is also Hidden
break;
}
As last note: if you're targeting Vista+ you may also check Task Dialog instead of writing a custom form (you may keep it as fallback for XP's users).

public bool var not updating its value

I've created a public bool LogedIn; in my login.cs:
if(login successful condition)
LogedIn = true;
else
LogedIn = false
But when I access this var from another form with Login Log = new Login();
by using if(Log.LogedIn) the LogedIn variable is always false, even after successful login by the user.
Why this is not working/updating its value outside its parent form?
Updating the code:
Login.cs
public bool isLogedIn;
private void button1_Click(object sender, EventArgs e)
{
if (i>-1 && (textBox2.Text == DS.Tables[0].Rows[--i][0].ToString()))
{
this.DialogResult = DialogResult.OK;
isLogedIn = true;
}
else
{
MessageBox.Show("Invalid password supplied for username \"" + comboBox1.Text + "\"", "Login Error.....", MessageBoxButtons.OK);
isLogedIn = false;
return;
}
}
Checking for the updated value in Home.cs
private void Home_Load(object sender, EventArgs e)
{
if (Log.isLogedIn) // Always False at this position.
{
label18.ForeColor = System.Drawing.Color.Green;
submitButton.Enabled = true;
}
else
{
label18.ForeColor = System.Drawing.Color.Red;
submitButton.Enabled = false;
}
}
I've checked again... I'm not having double instance of this variable in Login.cs form.
Here's how I'm calling Login.cs form via Home.cs (main form). Hope this helps...
private void loginToolStripMenuItem_Click(object sender, EventArgs e)
{
Log.FormClosed += new FormClosedEventHandler(Log_FormClosed);
Log.ShowDialog(this);
Log.BringToFront();
}
void Log_FormClosed(object sender, FormClosedEventArgs e)
{
if (Log.isLogedIn)
{
// Something here
}
else
{
// Something here
if (Log.DialogResult == DialogResult.Cancel)
Log.Hide();
}
}
I assume you have a form called Login in your application. Ignore the rest if assumption is wrong.
You are not referring to the correct instance of the Login form. In windows application, there is a collection called Application.OpenForms. This contains all the open form instances in your application. To access the correct Login form, try this:
Application.OpenForms.OfType<Form>().Where(x => x is Login).FirstOrDefault()
Make sure you have Login form always open to perform this task. You can make use of Hide instead of Close or CloseDialog for the Login form.
If you are closing the Login form, you can create static class which is accessible from each of the forms keep the properties there.
It seems that you have more than one instance of the Login class, each one with its isLogedIn var.
It is not clear where you are instantiating Login with your Login Log = new Login(); line. Have you tried to put a breakpoint there and see how many times it gets hit?
Another thing you could do is put a breakpoint on the line where isLogedIn is set, and another one where you read it. When the setting breakpoint is hit add a watch to the instance of Login (in this case add a watch to this) and choose Make Object ID from the right click menu. Your instance will be marjked by a "#1" Then do the same for the variable Log when the reading breakpoint is hit. If the mark is different (i.e. "#2") you can be sure that you are reading something different from the variable you set before.

Retain the dialog to be open after ShowDialog result

I'm opening a modal dialog asking the user to fill certain fields.
if(dlgUserDetail.ShowDialog() == DialogResult.OK)
{
}
On click of OK, the control comes to the parent form where I'm validating the user input.
If the validation fails, I wanted to keep the dialog to be open with the old values. Since it is modal dialog, the form gets closed.
It seems to be a common problem as I see many discussion on net, but nowhere I was able to find a solution.
Please let me know how to solve this problem. Thanks.
Regards
ArunDhaJ
If it is your dialog you could add a CancelEventArgs event called Validate or InputOk (similar to FileOk in OpenFileDialog) and have your main form check the input in a method. Before calling DialogResult = DialogResult.OK in your dialog, you add a ´onValidate` call to check if the input is valid.
{
// dialog
{
if (onValidate()) {
DialogResult = DialogResult.OK;
}
}
private bool onValidate() {
CancelEventHandler handler = Validate;
if (handler == null) {
return true;
}
CancelEventArgs args = new CancelEventArgs();
handler(this, args);
return args.Cancel;
}
}
{
// form
{
dlgUserDetail.Validate += valid;
if(dlgUserDetail.ShowDialog() == DialogResult.OK) { }
}
private void valid(object sender, CancelEventArgs e) {
// check input and set
e.Cancel = true;
// if not valid
}
}
One solution is to put validate logic into dlgUserDetail form and invoke it on OnClosing event. If the validation failed then prevent the form from closing.

Preventing a dialog from closing in the button's click event handler

I have a dialog that I show with <class>.ShowDialog(). It has an OK button and a Cancel button; the OK button also has an event handler.
I want to do some input validation in the event handler and, if it fails, notify the user with a message box and prevent the dialog from closing. I don't know how to do the last part (preventing the close).
You can cancel closing by setting the Form's DialogResult to DialogResult.None.
An example where button1 is the AcceptButton:
private void button1_Click(object sender, EventArgs e) {
if (!validate())
this.DialogResult = DialogResult.None;
}
When the user clicks button1 and the validate method returns false, the form will not be closed.
Given that you've specified you want a pop error dialog, one way of doing this is to move your validation into a OnClosing event handler. In this example the form close is a aborted if the user answers yes to the question in the dialog.
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Determine if text has changed in the textbox by comparing to original text.
if (textBox1.Text != strMyOriginalText)
{
// Display a MsgBox asking the user to save changes or abort.
if(MessageBox.Show("Do you want to save changes to your text?", "My Application",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
// Cancel the Closing event from closing the form.
e.Cancel = true;
// Call method to save file...
}
}
}
By setting e.Cancel = true you will prevent the form from closing.
However, it would be a better design/user experience to display the validation errors inline (via highlighting the offending fields in some way, displaying tooltips, etc.) and prevent the user from selecting the OK button in the first place.
Don't use the FormClosing event for this, you'll want to allow the user to dismiss the dialog with either Cancel or clicking the X. Simply implement the OK button's Click event handler and don't close until you are happy:
private void btnOk_Click(object sender, EventArgs e) {
if (ValidateControls())
this.DialogResult = DialogResult.OK;
}
Where "ValidateControls" is your validation logic. Return false if there's something wrong.
You can catch FormClosing an there force the form to remain opened.
use the Cancel property of the event argument object for that.
e.Cancel = true;
and it should stop your form from closing.
This doesn't directly answer your question (other already have), but from a usability point of view, I would prefer the offending button be disabled while the input is not valid.
Use this code:
private void btnOk_Click(object sender, EventArgs e) {
if (ValidateControls())
this.DialogResult = DialogResult.OK;
}
The problem of it is that the user has to clic two times the buttons for closing the forms;
Just add one line in the event function
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
{
this->DialogResult = System::Windows::Forms::DialogResult::None;
}
I wish I had time to find a better example, but you would be much better off using the existing windows forms validation techniques to do this.
http://msdn.microsoft.com/en-us/library/ms229603.aspx
void SaveInfo()
{
blnCanCloseForm = false;
Vosol[] vs = getAdd2DBVosol();
if (DGError.RowCount > 0)
return;
Thread myThread = new Thread(() =>
{
this.Invoke((MethodInvoker)delegate {
picLoad.Visible = true;
lblProcces.Text = "Saving ...";
});
int intError = setAdd2DBVsosol(vs);
Action action = (() =>
{
if (intError > 0)
{
objVosolError = objVosolError.Where(c => c != null).ToArray();
DGError.DataSource = objVosolError;// dtErrorDup.DefaultView;
DGError.Refresh();
DGError.Show();
lblMSG.Text = "Check Errors...";
}
else
{
MessageBox.Show("Saved All Records...");
blnCanCloseForm = true;
this.DialogResult = DialogResult.OK;
this.Close();
}
});
this.Invoke((MethodInvoker)delegate {
picLoad.Visible = false;
lblProcces.Text = "";
});
this.BeginInvoke(action);
});
myThread.Start();
}
void frmExcellImportInfo_FormClosing(object s, FormClosingEventArgs e)
{
if (!blnCanCloseForm)
e.Cancel = true;
}
You can probably check the form before the users hits the OK button. If that's not an option, then open a message box saying something is wrong and re-open the form with the previous state.

Categories

Resources