Reputation: 567
I have two forms:
The first form (XML Data Loader) contains a DataGridView with six columns (Name, Width, Height, Length, Dead Weight, Load Capacity)
XML Data Loader also has a button on it, which when pressed opens a new forms window (Add New Car). Add New Car has six textboxes where train car data is input by a user.
The goal is for the user to be able to click the Save button on Add New Car and the data will be pushed into a new row in the DataGridView on XML Data Loader, but I am having an issue with actually finding a way to do this. Everything else I've found assumes that DataGridViews are being populated through a database, but mine is user-input populated.
public partial class XMLDataLoader : Form
{
public XMLDataLoader()
{
InitializeComponent();
}
private void buttonAddCar_Click(object sender, EventArgs e)
{
AddNewCar addNewCar = new AddNewCar();
addNewCar.Show();
}
}
public partial class AddNewCar : Form
{
public AddNewCar()
{
InitializeComponent();
}
private void buttonNewSave_Click(object sender, EventArgs e)
{
//Check that all textboxes have some kind of entry
//ToDo: check the type of data so that only numbers are entered into non-name categories
if(textBoxNewName.TextLength < 1)
{
MessageBox.Show("Please enter a train name!");
}
if (textBoxNewWidth.TextLength < 1)
{
MessageBox.Show("Please enter a train width!");
}
if (textBoxNewHeight.TextLength < 1)
{
MessageBox.Show("Please enter a train height!");
}
if (textBoxNewLength.TextLength < 1)
{
MessageBox.Show("Please enter a train length!");
}
if (textBoxNewDeadWeight.TextLength < 1)
{
MessageBox.Show("Please enter a train dead weight!");
}
if (textBoxNewLoadCapacity.TextLength < 1)
{
MessageBox.Show("Please enter a train load capacity!");
}
//Save all data input by user to create a new train momentarily
var newTrainName = textBoxNewName.Text;
var newTrainWidth = textBoxNewWidth.Text;
var newTrainHeight = textBoxNewHeight.Text;
var newTrainLength = textBoxNewLength.Text;
var newTrainDeadWeight = textBoxNewDeadWeight.Text;
var newTrainLoadCapacity = textBoxNewLoadCapacity.Text;
}
}
Upvotes: 2
Views: 1752
Reputation: 567
Hat tip to @Ed Plunkett for the help - it's working swimmingly now!!
public partial class XMLDataLoader : Form
{
public XMLDataLoader()
{
InitializeComponent();
}
//Function for the Add Car button to open the Add New Car window
private void buttonAddCar_Click(object sender, EventArgs e)
{
AddNewCar displayNewCarWindow = new AddNewCar();
displayNewCarWindow.ShowDialog();
dataGridViewMainCarDisplay.Rows.Add(displayNewCarWindow.NewTrainName
, displayNewCarWindow.NewTrainWidth
, displayNewCarWindow.NewTrainHeight
, displayNewCarWindow.NewTrainLength
, displayNewCarWindow.NewTrainDeadWeight
, displayNewCarWindow.NewTrainLoadCapacity);
}
//Function for the Remove Car button to delete the currently
//selected car from the datagridview
private void buttonRemoveCar_Click(object sender, EventArgs e)
{
}
}
}
public partial class AddNewCar : Form
{
public AddNewCar()
{
InitializeComponent();
}
//Get and Private Set methods to pass textbox data to XMLDataLoader form
public String NewTrainName { get; private set; }
public String NewTrainWidth { get; private set; }
public String NewTrainHeight { get; private set; }
public String NewTrainLength { get; private set; }
public String NewTrainDeadWeight { get; private set; }
public String NewTrainLoadCapacity { get; private set; }
private void buttonNewSave_Click(object sender, EventArgs e)
{
//Check that all textboxes have some kind of entry
//ToDo: check the type of data so that only numbers are entered into non-name categories
var message = String.Empty;
if(textBoxNewName.TextLength < 1)
{
message += "Please enter a train name!\n";
}
if (textBoxNewWidth.TextLength < 1)
{
message += "Please enter a train width!\n";
}
if (textBoxNewHeight.TextLength < 1)
{
message += "Please enter a train height!\n";
}
if (textBoxNewLoadCapacity.TextLength < 1)
{
message += "Please enter a train length!\n";
}
if (textBoxNewDeadWeight.TextLength < 1)
{
message += "Please enter a train dead weight!\n";
}
if (textBoxNewLength.TextLength < 1)
{
message += "Please enter a train load capacity!\n";
}
//Save all data input by user to create a new train
NewTrainName = textBoxNewName.Text;
NewTrainWidth = textBoxNewWidth.Text;
NewTrainHeight = textBoxNewHeight.Text;
NewTrainLength = textBoxNewLoadCapacity.Text;
NewTrainDeadWeight = textBoxNewDeadWeight.Text;
NewTrainLoadCapacity = textBoxNewLength.Text;
//Handle the form execution for whether or not a textbox is empty
if (message != String.Empty)
{
MessageBox.Show(message);
}
else
{
DialogResult = DialogResult.OK;
}
}
//Function for the Cancel button to close the Add New Car window
private void buttonNewCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
Upvotes: 0
Reputation: 37059
First, use ShowDialog()
instead of Show()
. That way, you will still be in buttonAddCar_Click
when the AddNewCar
dialog closes. The way your code is now, buttonAddCar_Click
will exit while AddNewCar
is still visible, and your main window will have lost all contact with the instance of AddNewCar
that you created.
Secondly, you need to expose the text box values to the caller. So after the dialog closes, addNewCar.textBoxNewName.Text
will contain the string the user typed into the New Name TextBox
. But by default that's not public. So add a bunch of properties to expose the values:
public String NewName { get { return textBoxNewName.Text; } }
In buttonAddCar_Click
after the call to ShowDialog()
, you can do whatever you like with the exposed Text
properties of all those TextBoxes.
I don't do winforms every day now, so it's possible that textBoxNewName.Text
may throw an exception if you touch it after the form closes. Easy fix! Declare the public properties as regular properties instead of get-only accessors...
public String NewName { get; protected set; }
...and assign them their values in the OK click event when the user's input passes validation. Which is our next topic.
Lastly, making the user click on (potentially) six popups in succession is enough to make him commit suicide. Instead, I'd recommend declaring a string variable called message
and concatenating:
string message = "";
if(textBoxNewName.TextLength < 1)
{
message += "Please enter a train name!\n"
}
if (textBoxNewWidth.TextLength < 1)
{
message += "Please enter a train width!\n";
}
// ...etc....
if (!String.IsNullOrWhiteSpace(message))
{
MessageBox.Show(message);
}
else
{
NewName = textBoxNewName.Text;
// ...and so on for the other five properties.
// This will close the form and cause ShowDialog() to
// return DialogResult.OK
DialogResult = DialogResult.OK;
}
Form.DialogResult
is a useful adjunct to Form.ShowDialog()
.
If you have a Cancel button, it doesn't even need a Click method. Just set that Button
's DialogResult
property to DialogResult.Cancel
in the form designer, and it'll assign that value to Form.DialogResult
when the user clicks it, which will cause the window to close and ShowDialog
to return DialogResult.Cancel
.
Another way you could do this is declare a simple class which has all the car-creation data in it: NewName
, Width
, etc. Write an overload of ShowDialog()
which returns that type, or which takes a reference to that type and returns bool
(true for OK). If user cancels it returns null or false; if user clicks OK and passes validation, it returns an instance of that class, or in the reference version, populates the members of the reference that was passed in, and then returns true.
If you already have a class which represents a Car (from Entity Framework or whatever), you would just use that.
But the way I've described above is consistent with usage in built-in WinForms dialogs like FileOpen
and so on. My touchstone when working in any environment like WinForms, MFC, WPF, etc. is What Would the Framework Do? That's almost invariably the right answer, because a) successful frameworks tend to be reasonably well designed (they are used successfully by people who can't access their internals or consult their implementors), and b) anybody who interacts your code will know exactly what to expect because he already knows the framework's way of doing things.
Every time I use third party code that thinks it's smarter than the framework, I can't help noticing how much dumber it is.
Upvotes: 2