I'm having some trouble with my code regarding a Windows Form Application.
I have a form, that requires the user to enter some data for a new record in the database. I can successfully create a new "Order" in my Database. After I do that, I want to open a form that shows the user all details of the order. Therefore I take an already existing window and want the bindingSource to jump to a certain position.
My Code is as follows:
The "newOrder form"
//do stuff for the creation
//open a customerDetails window with the new entry
//resolve index of the new item
int newIndex = ordersBindingSource.Find("OrderID", newOrderID);
//create a new window and pass the index in the constructor
Order orderDetailsView = new Order(newIndex);
//show the new window and dispose the old one
orderDetailsView.Show();
this.Close();
this.Dispose();
The "Order form" constructor i'm calling:
public Order(int newIndex)
{
//initialize
InitializeComponent();
//set index and repaint
this.ordersBindingSource.Position = newIndex;
this.ordersBindingSource.ResetCurrentItem();
}
This is simply not working and I get the first entry of the dataset.
What am I doing wrong?
Where do you initialize you BindingSource from "Order form"? Make sure your newIndex <= ordersBindingSource.Count().
Try this:
//Form Order
int currentOrder = 0;
//constructor
public Order(int newIndex)
{
//initialize your variable here
currentOrder = newIndex;
//initialize
InitializeComponent();
}
//Create a void method that sets the BindingSource position
void SetupForm()
{
ordersBindingSource.Position = currentOrder;
}
// Override the OnLoad event and call the SetupForm() method here
protected override OnLoad(EventArgs e)
{
SetupForm();
}
Related
In one of my current projects, I have been attempting to develop a system that will take data input from textboxes on one form, and input them into a list on another form so that they may be displayed via a listbox and labels on another form as a data reference for manual input into a database.
//Create Attendance Report Instance
AttendanceReport report = new AttendanceReport();
private void inputButton_Click(object sender, EventArgs e)
{
try
{
//Declare Variables
string administratorVerify = verificationBox.Text;
//Inputs Change Based on NewStudent Check
if (passwordInput.Text == passwordTextBox.Text)
{
//Save Changes
Save();
}
Relevant Section => else if (newStudentCheck.Checked == true)
{
//New Verification Instance
VerificationClass verify = new VerificationClass();
//Verification Gateway
if (verify.Verify(administratorVerify) == true)
{
//Send Student to Attendance Report List
report.DisplayStudent();
}
else
{
MessageBox.Show("Unauthorized Password\nOnly Authorized Administrators May Access this Function");
}
}
//Clear Inputs
clearInputs();
}
I designed the part of the program that retrieves the data and displays it to function off of an universal instance of the second form, calling an instance of the first form to retrieve the data. I originally had the program create a new instance of the second form whenever the input button was clicked, before I moved the instantiation out of that block, making it a universal instance.
List<NewStudent> studentList = new List<NewStudent>();
private void RetrieveStudentInfo(NewStudent student)
{
//Temp Variables
int ID;
int Grade;
//Create MainForm Instance
MainForm reference = new MainForm();
//Get Values
student.Class = reference.classBox.Text;
student.Name = reference.nameBox.Text;
if (int.TryParse(reference.idBox.Text, out ID))
{
student.ID = ID;
}
else
{
MessageBox.Show("Invalid ID");
}
student.Password = reference.createPasswordBox.Text;
student.District = reference.districtBox.Text;
student.Country = reference.countryBox.Text;
if (int.TryParse(reference.gradeBox.Text, out Grade))
{
student.Grade = Grade;
}
else
{
MessageBox.Show("Invalid Grade");
}
}
public void DisplayStudent()
{
//Create Object
NewStudent student = new NewStudent();
//Get Student Info
RetrieveStudentInfo(student);
//Add Object to List
studentList.Add(student);
//Add Entry to Selection
newStudentSelection.Items.Add(student.ID);
}
private void newStudentSelection_SelectedIndexChanged(object sender, EventArgs e)
{
//Get Selected Item
int index = newStudentSelection.SelectedIndex;
//Display Data
classOutput.Text = studentList[index].Class;
nameOutput.Text = studentList[index].Name;
idOutput.Text = studentList[index].ID.ToString();
passwordOutput.Text = studentList[index].Password;
districtOutput.Text = studentList[index].District;
gradeOutput.Text = studentList[index].Grade.ToString();
countryOutput.Text = studentList[index].Country;
}
For all my life, from where I stand it seems like this program should work. I Intellisense is giving me no styntax errors, and I have attempted to review my logic with fellow amateur programmers in person, but for what ever reason, the data will not output to the controls on the second form. The only I can think of is that somehow by reference variables I pass as arguments to my RetrieveStudentInfo method and such are not actually getting passed somehow, but that shouldn't be correct.
Any advice on this situation would be greatly appreciated.
How to Close background Forms whenever a new form is opened in Windows Forms C#?
It should not be the specific form to be closed.
It should close all the background forms whenever a form is opened.
Two approaches.
First is using Application.OpenForms like this:
foreach (Form form in Application.OpenForms)
{
if(Form is YourMainFormClassName) //Check if current form is your main form and do not close it since your app would close. You can use .Hide() if you want
return;
form.Close();
}
Other approach is using List but you cannot do List<Form> because when removing you will have problem if you want to remove specific form and you go like yourList.Remove(this) it will remove all items with class of that form. Of course it will happen only if you open one form multiple times but to avoid that we will use Form.Tag property.
An Object that contains data about the control. The default is null
So we will use it to store our Id of the form.
So now when we prepared system let's write it:
First we need List<Form> that is accessible from all classes so we will create it like public static property.
public static class Settings //Class is also static
{
public static List<Form> OpenedForms = new List<Form>();
public static int MaxIdOfOpenedForm() //With this method we check max ID of opened form. We will use it later
{
int max = -1;
foreach(Form f in OpenedForms)
{
if(Convert.ToInt32(f.Tag) > max)
max = Convert.ToInt32(f.Tag);
}
return max;
}
public static void RemoveSpecificForm(Form form) //Remove specific form from list
{
for(int i = 0; i < OpenedForms.Count; i++)
{
if((OpenedForms[i] as Form).Tag == form.Tag)
{
OpenedForms.Remove(form);
return;
}
}
}
public static void CloseAllOpenedForms()
{
for(int i = 0; i < OpenedForms.Count; i++)
{
OpenedForms.Remove(OpenedForms[i]);
}
}
}
Now we have list but need to populate it every time we open new form so we will do it like this:
public partial class YourForm
{
public YourForm()
{
InitializeComponents();
this.Tag = Settings.MaxIdOfOpenedForm() + 1; //We are setting Tag of newly opened form
Settings.OpenedForms.Add(this); //Adding new form to opened forms.
}
}
And when we close form we need to remove form from list:
private void YourFormClosed(object sender, EventArgs e)
{
RemoveSpecificForm(this);
}
and when we set this up just call CloseAllOpenedForms().
This method could have some improvements in performance but this is basic and you expand it further.
well as only one form can be active and in the foreground, so when openening a new form you can close the previous one:
In your main form:
Form previous_form = null;
and when creating any form:
if( previous_form != null)
previous_form.Close();
SomeForm someform = new SomeForm();
previsous_form = some_form;
someform.Show();
I have this code, in which I read the data i deserialized in a gridview, let's name it FormReadDatabases
It gets populated like this:
xmlData = (xml.ServiceConfig)serializer.Deserialize(reader);
dataGridView1.DataSource = xmlData.Databases;
Then in each row of the grid I have a button 'Tables'
After I click it a new form appears FormReadTables
It gets populated like this:
BindingList<xml.Table> table = new BindingList<xml.Table>();
dataGridView4.DataSource = table;
Then I have a button which helps me add a new table, it works fine, the new row appears in the FormReadTables, But when i close the form and I am now at the FormReadDatabases if I click again on the Table button the changes are not saved.
Any idea how to avoid this?
This should be simple, data binding needs to happen using a mechanism that can hold value even when forms are opened or closed:
First way could be use a static type as follows:
static BindingList<xml.Table> table;
public BindingList<xml.Table> FetchTable()
{
if(table == null)
{
table = new BindingList<xml.Table>();
}
return table
}
dataGridView4.DataSource = FetchTable();
There's a catch out here what if the form can have multiple instances than can access the static variable, then while updating the table type it needs to be locked / synchronized
Another option would be table type is part of the main form, which loads the child form and in the constructor of the child form it gets the instance of the parent form, which is used updated and is retained even after closing child form. This will also need synchronization for multiple user / thread access
public class ParentForm
{
public BindingList<xml.Table> table = new BindingList<xml.Table>();
}
public class ChildForm
{
ParentForm localPf;
pulic ChildForm(ParentForm pf)
{
localPf = pf;
}
dataGridView4.DataSource = localPf.table;
}
Noe any change to parent form object's table variable will persist till the point Parent form is in the memory, but please note this implementation is not yet threads safe
Each time the form opens, you are creating a new BindingList.
BindingList<xml.Table> table = new BindingList<xml.Table>();
Instead, have the other page contain a variable for this, and when you 'new' the other form, pass in the variable.
The Actions taken on the opened form are byref, and therefore will update your host forms variable. This means the next time you open the form, the variable you pass to it will already have the previous changes already stored in it.
Example as requested:
I don't have my WinForms environment at hand, but this shows the important concepts.
namespace Bob
{
public class FormLucy
{
private BindingList<xml.Table> table = new BindingList<xml.Table>();
// your form stuff..
protected void ButtonClick(object sender, EventArgs e)
{
var frm = new FormTracy(table);
// init your forms properties, position etc
fmr.ShowDialog();
}
}
}
Scenario:
A child form which is made visible via a button.
A delegate is created to run certain code when this child is closed.
The child form is used to edit the underlying data
When the child form is closed the latest version of the data should be displayed on any bound controls on the parent form.
Question -
Here is the relevant code attempt:
public partial class uxRevisionHelperForm : Form
{
public SqlCeConnection conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["WindFormAppRevisionHelper.Properties.Settings.DefinitionsDBConnectionString"].ConnectionString);
BindingSource definitionsBindingSource = new BindingSource();
public uxRevisionHelperForm()
{
InitializeComponent();
uxDescriptionTextBox.AutoSize = true;
refreshBindingSource();
assignControlsToSource();
}
//>>>>>>>>ALL OF THE FOLLOWING METHOD IS CALLED BY THE DELEGATE WHEN THE CHILD IS CLOSED
public void refreshBindingSource()
{
SqlCeDataAdapter da = new SqlCeDataAdapter(new SqlCeCommand("Select * From tb_RevisionDefinitions",conn));
DataSet ds = new DataSet("Helper");
ds.Tables.Add("DefinitionsTable");
da.Fill(ds.Tables["DefinitionsTable"]);
// Assign the BindingSource.
definitionsBindingSource.DataSource = ds.Tables["DefinitionsTable"];
uxBindingNavigator.BindingSource = this.definitionsBindingSource;
}
void assignControlsToSource()
{
uxDescriptionTextBox.DataBindings.Add(new Binding("Text", definitionsBindingSource, "Description", true));
uxWordPhraseTextBox.DataBindings.Add(new Binding("Text", definitionsBindingSource, "WordPhrase", true));
uxReferenceTextBox.DataBindings.Add(new Binding("Text", definitionsBindingSource, "Reference", true));
}
private void uxUpdateDataButton_Click(object sender, EventArgs e)
{
uxRevisionHelperGroupBox.Enabled = false;
uxBindingNavigator.Hide();
uxFormDatabase myNewDisplay = new uxFormDatabase();
myNewDisplay.FormClosed += delegate { activateGroupBorder(); };
myNewDisplay.Show();
}
public void activateGroupBorder()
{
uxRevisionHelperGroupBox.Enabled = true;
uxBindingNavigator.Show();
refreshBindingSource(); //<<<<<<<<<<<DELEGATE CALLS THIS METHOD
}
}
The above seems to work but do I really have to run all the code in the method refreshBindingSource to make sure the info displayed on the parent form is up-to-date ?
UPDATE
I've followed Amiram's advice and passed in my BindingSource so as not to have to repeat code already in place for the parent form. I've copied in some boiler plate code the method saveToolStripButton_Click; ... really don't know what is going on in that small routine - will those two lines will suffice for saving info back to the database?
public partial class uxFormDatabase : Form
{
BindingSource rawtableBindingSource = null;
public uxFormDatabase(BindingSource myPassedSource)
{
InitializeComponent();
rawtableBindingSource = myPassedSource;
uxDGVtable.AutoSize = true;
uxDGVtable.SizeChanged += new EventHandler(uxDGVtable_change);
dataToDGV();
}
public void uxDGVtable_change(object sender, EventArgs e)
{
if (uxDGVtable.Width < 1158)
{
this.Width = uxDGVtable.Width;
}
}
public void dataToDGV()
{
uxrawdataBindingNavigator.BindingSource = this.rawtableBindingSource;
uxDGVtable.DataSource = this.rawtableBindingSource;
}
private void saveToolStripButton_Click(object sender, EventArgs e)
{
Validate();
rawtableBindingSource.EndEdit();
}
}
If you used different data source for both forms them you have no choice but to reload data (there is a way to automate that with sql server), but you can avoid that if you'll use the same dataset or even the same BindingSource, so the refresh will happen automatically.
I have a main form that has most of the functionality in it. I was just wondering how would I pass on a variable from say a pop up form, to that main form.
Like for instance:
I have a main form that needs some connection info. So when you click the button "Enter Connection Info", it opens up a new form that the user can type in the IP Address he wants to use for his connection.
On this new form, I have a textbox and a button and once you enter the information it should close and pass on the string that contains the ip back to the original form.
Any suggestions? Do you think there is a better method of accomplishing this than using a windows form, and just going ahead and using a windows form or something? I'm quite perplexed on this issue at the moment.
Expose the textbox text as a public read only property. Show the connection form as a dialog and when it closes, get the connection from the property and then dispose the form:
in open form handler (button click, menu, whatever)
string connectionString = null;
using (ConnectionForm form = new ConnectionForm())
{
DialogResult result = form.ShowDialog();
if (result == DialogResult.Ok)
connectionString = form.ConnectionString
}
In you connection form:
public class ConnectionForm: Form
{
....
public string ConnectionString { get { return textBox1.Text; } }
}
You can create a public property in your main form and pass main form instance in pop-up constructor. In this way you can change the main form property.
You can also create an event in your pop-up form and hook it in your main form.
I like to use a pattern sort of like this (bear with me, c# is not my first language):
public class ValueForm: Form
{
public static string GetFromUser(string originalValue)
{
using (ConnectionForm form = new ConnectionForm())
{
form.TheValue = originalValue;
var result = form.ShowDialog();
if (result == DialogResult.Ok)
return form.TheValue;
else
return originalValue;
}
}
public string TheValue {
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
/* also some code behind your OK & cancel buttons to set
DialogResult appropriately,
and do any validation that you need to do
*/
}
and then you would use this like:
string newValue = ValueForm.GetFromUser(oldValue);
Reference Bind the controls on the dialog Form to properties of the Parent Form.
public dlgDbConnProps ( Form Owner )
{
// TODO: Complete member initialization
InitializeComponent ( );
owner = Owner;
}
private void cbo_ProviderLst_SelectedIndexChanged ( object sender, EventArgs e )
{
owner.Provider = cboLst.Text;
}
Here is another method that I have implemented:
... pass a Func to the child form constructor:
public dlgRequestLogin ( Func<string, string, bool> LoginMethod )
{
InitializeComponent ( );
p_loginMethod = LoginMethod;
}
... then handle on button click (or other appropriate event):
private void cmd_SendLoginCredentials_Click ( object sender, EventArgs e )
{
bool res = p_loginMethod.Invoke ( txt_UserID.Text, txt_UserPassword.Text );
}