How to edit a database from another form c# - c#

I am completely new on Visual C#. I am trying to create a program with a database to register products and costumers. I just followed these 2 walktrhoughs:
Creating a Local Database File in Visual Studio
Connecting to Data in a Local Database File (Windows Forms)
Then I created 3 Forms on my solution:
Form1: splash screen that is hidden after some seconds and opens the Form2.
Form2: With 4 panels, [A] to add new and edit registers for products (I dragged and dropped the table in 'Details' mode), [B] with the DataGridView which cells are configured to read Only = true. The other 2 panels are the same for costumers.
Form3: a Dialog Box that opens when double click a cell from DataGridView. This dialog box shows a product data with just few fields editable.
My problem:
If I edit a field on Form2 [A] and save it I can see the changes on the DataGridView [B] and on the Form3.
If I edit a field on Form3 and save it, then close the dialog box, there is no change on Form2 neither on panel [A] nor [B]. But when I open the Form3 again the edited data is there. And if I edit the same field on [A] that I edited on Form3 and try to save , occurs the following error:
An unhandled exception of type 'System.Data.DBConcurrencyException' occurred in LojaEstiloDesign20150906.exe
Additional information: Concurrency violation: the UpdateCommand affected 0 of the expected 1 records."
This seems to be a very basic problem, but I have no idea how to solve it. I already tried lot of things but none have worked.
Any help will be very appreciated.
Form2:
namespace LojaEstiloDesign20150906
{
public partial class frm_Menu : Form
{
public frm_Menu()
{
InitializeComponent();
}
private void CadProdutosToolStripMenuItem_Click(object sender, EventArgs e)
{
panel_CadastroProdutos.Visible = true;
panel_CadastroProdutos.Dock = DockStyle.Fill;
panel_CadastroClientes.Visible = false;
panel_ConsultaClientes.Visible = false;
panel_ConsultaProdutos.Visible = false;
}
private void CadClientesToolStripMenuItem_Click(object sender, EventArgs e)
{
panel_CadastroClientes.Visible = true;
panel_CadastroClientes.Dock = DockStyle.Fill;
panel_CadastroProdutos.Visible = false;
panel_ConsultaClientes.Visible = false;
panel_ConsultaProdutos.Visible = false;
}
private void ConProdutosToolStripMenuItem1_Click(object sender, EventArgs e)
{
panel_ConsultaProdutos.Visible = true;
panel_ConsultaProdutos.Dock = DockStyle.Fill;
panel_CadastroClientes.Visible = false;
panel_ConsultaClientes.Visible = false;
panel_CadastroProdutos.Visible = false;
}
private void ConClientesToolStripMenuItem1_Click(object sender, EventArgs e)
{
panel_ConsultaClientes.Visible = true;
panel_ConsultaClientes.Dock = DockStyle.Fill;
panel_CadastroClientes.Visible = false;
panel_ConsultaProdutos.Visible = false;
panel_CadastroProdutos.Visible = false;
}
private void frm_Menu_FormClosing(object sender, FormClosingEventArgs e)
{
Application.Exit();
}
private void produtosBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.produtosBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.lojaEstiloDataSet);
}
private void frm_Menu_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'lojaEstiloDataSet.Clientes' table. You can move, or remove it, as needed.
this.clientesTableAdapter.Fill(this.lojaEstiloDataSet.Clientes);
// TODO: This line of code loads data into the 'lojaEstiloDataSet.Produtos' table. You can move, or remove it, as needed.
this.produtosTableAdapter.Fill(this.lojaEstiloDataSet.Produtos);
}
private void produtosDataGridView_CellMouseDoubleClick(object sender, DataGridViewCellMouseEventArgs e)
{
frm_FichaProdutos frm3 = new frm_FichaProdutos();
frm3.Show();
}
private void toolStripButton6_Click(object sender, EventArgs e)
{
this.Validate();
this.clientesBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.lojaEstiloDataSet);
}
}
}
Form3:
namespace LojaEstiloDesign20150906
{
public partial class frm_FichaProdutos : Form
{
public frm_FichaProdutos()
{
InitializeComponent();
}
private void frm_FichaProdutos_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'lojaEstiloDataSet.Produtos' table. You can move, or remove it, as needed.
this.produtosTableAdapter.Fill(this.lojaEstiloDataSet.Produtos);
// TODO: This line of code loads data into the 'lojaEstiloDataSet.Produtos' table. You can move, or remove it, as needed.
this.produtosTableAdapter.Fill(this.lojaEstiloDataSet.Produtos);
}
public void produtosBindingNavigatorSaveItem_Click_1(object sender, EventArgs e)
{
this.Validate();
this.produtosBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.lojaEstiloDataSet);
}
}
}

ADO.NET uses optimistic concurrency by default. That means that it stores two versions of the data (original and current) and then, when you try to save modifications to existing records, it compares the original version to whats in the database to make sure that they match before saving. The idea is that it prevents two users both retrieving the same data and both trying to save changes and having the second save overwrite the changes made in the first.
In your case, it's not two different users with two different application instances though. It's two forms within the same application instance. Your are retrieving the data in the first form, retrieving the data in the second form, saving changes from the second form and then trying to save changes from the first form. The original version of the data in the first form does not match what is in the database and so a concurrency violation occurs.
You have two choices as to how to proceed. In a valid concurrency violation, i.e. two different users, you would catch the exception and then decide what to do, which would likely be to get the data again and have the user re-edit or possibly merge their changes. That's not the way to go in your case. You should either throw away the data that you have in the first form and get it again when the second form closes or else don't get the same data twice in the first place.
In that second option, instead of the second form getting its own data, the first form could pass it the data that it already has. Because there is only one copy of the data, it will always remain in sync with the database.

Related

Why can I not call a form object in two events?

I'm making like a add contact form with two buttons, ADD CONTACT and EDIT CONTACT. When a user clicks add contact, it pops up another form where the user can add contact information.
I want to give them the option to edit that info by clicking the EDIT CONTACT button which should pop up the SAME form.
However its not letting me call the object of the form twice, saying that I cannot press the edit button after the add button.
How do I call a form object twice?
//instatiating an object of the form
FormContact contactForm = new FormContact();
public FormManager()
{
InitializeComponent();
}
private void btnAdd_Click(object sender, EventArgs e)
{
//displaying it when the user clicks add button
contactForm.Show();
}
private void btnEdit_Click(object sender, EventArgs e)
{
//trying to display it again but gives this exception
///System.ObjectDisposedException: 'Cannot access a disposed
///object.
///Object name: 'FormContact'.'
contactForm.Show();
}
Error:
///System.ObjectDisposedException: 'Cannot access a disposed
///object.
///Object name: 'FormContact'.'
The problem is you're closing the form after you've shown it.
You click the Show button
Your only instance of the form is shown
You close it with the X in the top corner
The runtime destroys the form (disposes it) after it is closed
You try to show it again but this this it's gone, trashed, doesn't exist any more, waiting to be garbage collected
Either make a new form each time you open it (to reduce code clutter, assign this same event handler to both button clicks, or copy paste it out twice if you want them to be coded differently eventually):
private void btnAddOrEdit_Click(object sender, EventArgs e)
{
new FormContact().Show();
}
Or intercept the FormClosing event of the FormContact form and cancel the closing, and perform a Hide() instead so that instead of being destroyed your form is made invisible. It will then still exist and can be Show()n the next time. To handle the event, open the FormContact designer, click anywhere in the form background, click lightning bolt in properties grid, double click the FormClosing entry:
private void FormClosing(object sender, FormClosingEventArgs e){
e.Cancel = true;
this.Hide();
}
Which method you choose depends how you want your program to behave:
If you make a new form each time, and you Show instead of ShowDialog your user could click Add twice and see two forms. Then could click Add 10 times and see 10 forms. Using ShowDialog means that the main window won't accept any more clicks until the FormContact is closed. You might or might not want this either
If you Hide (not close; hiding is different from closing) and Show the same form rather than making a new one then the user can click Add 10 times but they still only see one form
FormContact contactForm = new FormContact(); is a Member variable, it's scope is Private and is visible to the entire class.
After you first Show the form:
contactForm.Show();
The form is already showing. Therefore if you call Show again, it won't do anything as the instance of the form/class is already showing.
If you want to show two instances of the form, you will need to instantiate two instances eg:
private void btnAdd_Click(object sender, EventArgs e)
{
FormContact contactForm = new FormContact();
contactForm.Show();
}
private void btnEdit_Click(object sender, EventArgs e)
{
FormContact contactForm = new FormContact();
contactForm.Show();
}
Or make two instances of it:
FormContact contactForm1 = new FormContact();
FormContact contactForm2 = new FormContact();
private void btnAdd_Click(object sender, EventArgs e)
{
contactForm1.Show();
}
private void btnEdit_Click(object sender, EventArgs e)
{
contactForm2.Show();
}
Or add a argument in the parameter of the Constructor to indicate Add or Edit, eg:
public class FormContact
{
public FormContact(int id)
{
if (id > 0)
{
//Load contact for Editing
}
else
{
//Clear all fields for Adding
foreach(var ctrl in this.Controls)
{
if (ctrl Is TextBoxBase) ctrl.Text = string.Empty
//TODO other controls types... if (ctrl Is ....
}
}
}
}
Then you can call it passing a contactID to edit or 0 to add:
FormContact contactForm = new FormContact(contactID);
contactForm.Show();
I've got another answer, in both methods simply show your form modally:
contactForm.ShowModal();

DevExpress Gridview can't show data

I have this code :
private void frmWeld_Load(object sender, EventArgs e)
{
List<Weld> lst = _weldRepository.Get().ToList();
gridControl.DataSource = new BindingList<Weld>(lst) { AllowNew = true };
}
I want to load my data into devExpressGridView
As you can see my data is loaded but the gridview can't show the data and my break point doesn't pass from gridControl.DataSource = new BindingList<Weld>(lst) { AllowNew = true} and my program remains with this state.
Why?
I just add new column to my gridview after this the problems occurreded.
I use entity framework ,when i change the database my application creates a new database using code first and after that my data is lost but the problem that i said is solved.
Since your code is executing in Load event, add ForceInitialize() to your code.
private void frmWeld_Load(object sender, EventArgs e)
{
// your previous code
gridControl.ForceInitialize(); <- add this line
}

Pass parameter in an already opened form in C#

I want to pass a parameter to the textbox. I have the following code and it is passing the parameter but not the way I want.
My main form in already open and I want to pass the parameter from my search form. when I do with the code below it opens mt 1 more main form and the parameter is shown in there. I want to by able to show in the opened main form.
When I erase frmMain.Show(); nothing happens.
Main frmMain = new Main();
artikal = "TEST TEST";
frmMain.ed_artiakal.Text = artikal;
frmMain.Show();
any suggestions?
You have many variants to solve your problem.
Option 1
Define and use custom event.
Search form code:
public event EventHandler ArtikalTextChanged;
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (ArtikalTextChanged != null)
ArtikalTextChanged(this, EventArgs.Empty);
}
Main form code:
private void button1_Click(object sender, EventArgs e)
{
Search search = new Search();
search.ArtikalTextChanged += OnArtikalTextChanged;
search.Show();
}
private void OnArtikalTextChanged(object sender, EventArgs e)
{
this.ed_artiakal.Text = (sender as Search).textBox1.Text;
}
Don't forget to make textBox1 of Search form public.
Option 2
Get instance of your main form in search form:
Search form code:
private void textBox1_TextChanged(object sender, EventArgs e)
{
var mainForm = Application.OpenForms.OfType<Main>().FirstOrDefault();
mainForm.ed_artiakal.Text = textBox1.Text;
}
Main form code:
private void button1_Click(object sender, EventArgs e)
{
Search search = new Search();
search.Show();
}
Don't forget to make ed_artiakal control public in your Main form.
Option 3
Share data between forms (recommend)
But if you application is large and you want to make it scaleable and flexible I recommend you to use data-binding technique to share data between forms without coupling them. You can read more at articles: http://msdn.microsoft.com/en-us/library/h974h4y2(v=vs.90).aspx
I have solved my problem in the following way.
On my Search Form I created a public string and when I showed the form I referenced to that string in my case GetItemCode.
The key here was to use ShowDialog() and not to use Show().
SEARCH FORM
Search frmSearch = new Search();
frmSearch.ShowDialog();
ed_artiakal.Text = frmSearch.GetItemCode;
MAIN FORM
public string GetItemCode
{
get { return Artikal; }
}
Now when I close the search form the value is shown in the TextBox on my main form.
Thanks for your answers and comments!

Windows form doesn't stay open after it is opened

I'm writing a simple WinForms app that parses a text file for correct values, and as it finds an incorrect value, opens up a new form, which displays the incorrect or missing value, with the user being able to input the correct value. I have the problem where, for example, I'll deliberately put two incorrect values in my text file to check, and the form window closes immediately after its opened for the first error,and only stays open for the second error to be fixed.
foreach (string line in lines)
{
string[] items = line.Split('\t').ToArray();
for (int i = 0; i <custIndex.Count; i++)
{
int index = custIndex[i];
Globals.Code = items[index - 1].ToUpper();
if (!CountryList.ContainsKey(Globals.Code) && !StateList.ContainsKey(Globals.Code))
{
form2.textBox1.Text = Globals.Code;
form2.Show();//Shows form2 for user to enter correct input
}
}//inner for
}//inner for each
Here's the form 2 code (form 2 being instantiated at the beginning of the method before the looping):
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void textBox2_TextChanged(object sender, EventArgs e)
{
}
//
private void button1_Click(object sender, EventArgs e)
{
Globals.Code = textBox2.Text;
this.Close();
}
private void Form2_Load(object sender, EventArgs e)
{
}
}
The user is supposed to press the button after entering a new value for Globals.Code (I used a global variable, not sure if that was the most kosher way of doing things).After which the form closes and goes back to Form 1. I think form 2 is being displayed properly with the first error value from the text file, but it immediately opens and closes. Is there a way to keep the window open? I'm sorry if this is convoluted, I'm doing a lot of Winforms and I'm not really an expert on this stuff.
Thanks,
Amanda
Your best bet may be to use a modal dialog, so change form2.Show to form2.ShowDialog.
However, when using a global variable with a loop like that, the global variable will only have the last value put into the form after the loop is complete. If you use the ShowDialog approach, the call will block at that line until the user closes the dialog. After that point you can read the value from the textbox and do something with it.

Passing Data from datagridview to form C#

Hoping someone can shed some light on my problem. I followed the tutorial found here http://msdn.microsoft.com/en-us/library/ms171925(v=VS.100).aspx#Y3500 and cannot get this to work.
My code is as follows:
namespace CityCollectionCSharp
{
public partial class frmSwitch : Form
{
public frmSwitch()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'newCityCollectionDataSet.ClientTable' table. You can move, or remove it, as needed.
this.clientTableTableAdapter.Fill(this.newCityCollectionDataSet.ClientTable);
// TODO: This line of code loads data into the 'newCityCollectionDataSet.PropertyInformation' table. You can move, or remove it, as needed.
this.propertyInformationTableAdapter.Fill(this.newCityCollectionDataSet.PropertyInformation);
}
private void propertyInformationDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
System.Data.DataRowView SelectedRowView;
newCityCollectionDataSet.PropertyInformationRow SelectedRow;
SelectedRowView = (System.Data.DataRowView)propertyInformationBindingSource.Current;
SelectedRow = (newCityCollectionDataSet.PropertyInformationRow)SelectedRowView.Row;
frmSummary SummaryForm = new frmSummary();
SummaryForm.LoadCaseNumberKey(SelectedRow.CaseNumberKey);
SummaryForm.Show();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
propertyInformationBindingSource.Filter = "ClientKey ='" + comboBox1.SelectedValue + "'";
}
}
}
That is for the first form and now the second form:
namespace CityCollectionCSharp
{
public partial class frmSummary : Form
{
public frmSummary()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'newCityCollectionDataSet.PropertyInformation' table. You can move, or remove it, as needed.
this.propertyInformationTableAdapter.Fill(this.newCityCollectionDataSet.PropertyInformation);
}
internal void LoadCaseNumberKey(String CaseNumber)
{
propertyInformationTableAdapter.FillByCaseNumberKey(newCityCollectionDataSet.PropertyInformation, CaseNumber);
}
}
}
I have the query set up as follows in the propertyInfromationTableAdapter :
SELECT CaseNumberKey, BRTNumber, ParcelNumber, Premises, ClientKey, ParcelNum, Registry, TaxAcctName, StreetCode, CoverDate, OrderDate, Assessment, TaxFrom, TaxTo, TaxOpen, WaterOpen, WaterAcct, WaterTo, WaterFrom, AssessedBeg, AssessedDim, SumNotes, Legal, TotalWater, TotalTax, Type, OPARec, OPADoc, OPADocNum, Recital, Num, Name, Direction, Unit, ProductKey, DateFinished, Finished, Paid, BD, BDPaid, Search, Exam
FROM PropertyInformation
WHERE (CaseNumberKey = #CaseNumberKey)
I cannot figure out for the life of me why this does not work as prescribed. When I click on a record it passes both records in the table and always has the first one in the boxes I have. I only know this as I left the bindingnavigator. Any help would be much appreciated.
Whenever I have an issue getting to work off the net it boils down to me doing it / implementing it wrong, a misunderstanding of how something works and therefore it is going to break anyway or if the code is from a third party then it may not work to start or you find a bug.
It is unlikely the MSDN code is wrong (but not impossible) so I would suggest breakpoints galore in the code you have produced and if that doesn't enlighten then I would create a brand new project copying the code word for word may mean you see where you went wrong or if you get that working then slowly copy in what you have to see when it breaks.
Try this,
Load to Datagridview using sqldatareader
DataBinding between DataSet and DataGridView in C#
How to: Bind Data to the Windows Forms DataGridView Control
You can also use sqlDatareader,sqlDataAdapter to load on Datagridview Programatically..
Regards

Categories

Resources