My issue can seem so trivial, but unfortunately I don't know how to solve that problem.
There's one table in one database. I have to add the data with clicking on the button to that table. When user clicks on the button, he's getting to some form where he/she can input the data. At the first time it would be good if I am able to input: id, kind of service, price. I've decided to create a new class where I would content all variables including these three variables. These variable are public.
Also I've decided to read the text from the textBoxes and to write this information to the variables of that class. In the second form there are 2 buttons. "Ok" and "Cancel". And I have decided to use ShowDialog.
I'm capable to output the table from the database to the DataGridView, but I am not well-aware how to add the data to my table and showcase that successfully in the datagridview after the inserting.
My class:
public class AllDataDB
{
public int id_serv;
public double price;
public string name;
}
The second form:
public partial class TypeService : Form
{
public AllDataDB Class;
public TypeService(AllDataDB t)
{
Class = t;
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
private void button1_Click(object sender, EventArgs e)
{
AllDataDB Class = new AllDataDB();
Class.id_serv = Convert.ToInt32(textBox3.Text);
Class.name = NameService.Text;
Class.price = Convert.ToDouble(PriceService.Text);
this.DialogResult = DialogResult.OK;
this.Close();
}
}
The work of the button calling the form and the query:
private void NewServe_Click(object sender, EventArgs e)
{
AllDataDB Class = new AllDataDB();
TypeService form = new TypeService(Class);
if (form.ShowDialog() == DialogResult.OK)
{ // відповідно до класу створюється новий запис. INSERT.
SqlConnection Con = new SqlConnection(connectionString);
Con.Open();
string Que = "INSERT INTO type_service " +
"VALUES(" + Class.id_serv + " ,'" + Class.name +
"' ," + Class.price + " );" +
"SELECT * FROM type_service";
SqlCommand cmd = new SqlCommand(Que, Con);
cmd.ExecuteNonQuery();
Con.Close();
SqlDataAdapter sqlDa = new SqlDataAdapter("SELECT * FROM type_service", Con);
DataTable d = new DataTable();
sqlDa.Fill(d);
dataGridView3.AutoGenerateColumns = false;
dataGridView3.DataSource = d;
}
}
There are many problems in the code shown. The most important ones are the way in which you read the values and how do you try to insert in the data. Inside the form TypeService you create a new instance of the AllDataDB class where you store the results. This instance is no more the one you have passed in input, so you need to read the values from the instance created by the TypeService form (stored in the global field Class). The second problem is the string concatenation of your values. This is a well known problem leading to parsing problems and sql injection. It is fixed by a parameterized query as shown below
private void NewServe_Click(object sender, EventArgs e)
{
// Do no pass an instance of Class here, just pass null
// or remove it at all if you don't plan to reuse the form for updating
TypeService form = new TypeService(null);
if (form.ShowDialog() == DialogResult.OK)
{
// Add the using statement to ensure a proper release of resources.
using SqlConnection Con = new SqlConnection(connectionString);
Con.Open();
// Parameterized query
string Que = "INSERT INTO type_service VALUES(#id,#name,#price);";
SqlCommand cmd = new SqlCommand(Que, Con);
cmd.Parameters.Add("#id", SqlDbType.Int).Value = form.Class.id_serv;
cmd.Parameters.Add("#name", SqlDbType.NVarChar).Value = form.Class.name;
cmd.Parameters.Add("#price", SqlDbType.Decimal).Value = form.Class.price;
cmd.ExecuteNonQuery();
SqlDataAdapter sqlDa = new SqlDataAdapter("SELECT * FROM type_service", Con);
DataTable d = new DataTable();
sqlDa.Fill(d);
dataGridView3.AutoGenerateColumns = false;
dataGridView3.DataSource = d;
}
}
There are other minor problems. In the TypeService form and in the class AllDataDB you have used global fields instead of the more flexible way of using properties.
public class AllDataDB
{
public int id_serv {get;set;}
public double price {get;set;}
public string name {get;set;}
}
as well
public AllDataDB Class {get;set;}
also, given the null passed to the constructor of the TypeService form you now need to ensure to not use that Class properties without cheching for its null value
Well, this aid was very useful. Thanks. But I've resolved this problem with creating a new 3 variables in the class TypeService. These variables are public too. And that is looking like this:
In the class TypeService:
public int i;
public string n;
public double p;
In the class MainCore:
cmd.Parameters.Add("#id", SqlDbType.Int).Value = form.i;// form.Class.id_serv;
cmd.Parameters.Add("#name", SqlDbType.NVarChar).Value = form.n;//form.Class.name;
cmd.Parameters.Add("#price", SqlDbType.Decimal).Value = form.p; //form.Class.price;
So it works. And I can remove the class AllDataDB, because that is not important and useful now.
Thanks for help.
Related
I'm trying to build a Form that can insert images to local DB and load them to flowLayoutPanel. Here is the layout of my form, I insert images in 'admin' tab (pic.1).
In 'Browse Photos' tab I try to load photos of a specific city to flowLayoutPanel by clicking the button (pic.2).
Insert images
Load images according to button pressed
My local database (data type)
I inserted photos smoothly but got a problem when I tried to load them.
here is my code:
public Frm_MyAlbum()
{
InitializeComponent();
}
private void loadImage (int id, FlowLayoutPanel flp)
{
try
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = Settings.Default.Database1ConnectionString;
SqlCommand command = new SqlCommand();
command.CommandText = $"Select * from Photos where ID = {id}";
command.Connection = conn;
conn.Open();
SqlDataReader DR = command.ExecuteReader();
this.flowLayoutPanel1.Controls.Clear();
while (DR.Read())
{
byte[] bytes = (byte[])DR["Image"];
MemoryStream MS = new MemoryStream(bytes);
PictureBox pics;
pics = new PictureBox();
pics.Image = Image.FromStream(MS);
pics.Size = new Size(200, 160);
pics.SizeMode = PictureBoxSizeMode.StretchImage;
this.flowLayoutPanel1.Controls.Add(pics);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void GetID(string City, FlowLayoutPanel flp)
{
try
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = Settings.Default.Database1ConnectionString;
conn.Open();
SqlCommand command = new SqlCommand();
command.CommandText = $"Select * from Photos where City = {City}";
command.Connection = conn;
SqlDataReader DR = command.ExecuteReader();
while (DR.Read())
{
loadImage((int)DR["PhotoID"], flp);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void button1_Click(object sender, EventArgs e) //button London
{
this.flowLayoutPanel1.Controls.Clear();
GetID("London", flowLayoutPanel1);
}
private void button7_Click(object sender, EventArgs e) //button Add to DB
{
try
{
using (SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = Settings.Default.Database1ConnectionString;
SqlCommand command = new SqlCommand();
command.CommandText = $"Insert into Photos(City, Description, Image) values(#City, #Desc, #Image)";
command.Connection = conn;
byte[] bytes;
MemoryStream MS = new MemoryStream();
this.pictureBox1.Image.Save(MS, System.Drawing.Imaging.ImageFormat.Jpeg);
bytes = MS.GetBuffer();
command.Parameters.Add("#City", SqlDbType.Text).Value = this.textBox2.Text;
command.Parameters.Add("#Desc", SqlDbType.Text).Value = this.textBox1.Text;
command.Parameters.Add("#Image", SqlDbType.Image).Value = bytes;
conn.Open();
command.ExecuteNonQuery();
MessageBox.Show("Adding Successfully");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void button8_Click(object sender, EventArgs e) //button browse
{
if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
{
this.pictureBox1.Image = Image.FromFile(openFileDialog1.FileName);
}
}
When I ran the code, I pressed London (button1) and an exception showed up as "Invalid column name 'London'." VS indicates there's something wrong in the line 'command.CommandText = $"Select * from Photos where City = {City}";'.
the bug
Tried many ways to rewrite it but haven't figure it out.
What should I do to solve this issue?
Thank you guys in advance!!
**Short answer: ** the problem is in the commandtext of your query. You also forgot to add the parameter that contains the name of the city
Separate your data from your form (MVVM)
In modern programming there is a tendency to separate your data (=model) from the way that your data is displayed (=view).
Advantages of the separation is that you can reuse the model in other Views, you can change the model without having to change the view. For instance, if you decide to fetch your images from a file instead of a database, your Form won't have to notice. You can also change your View without having to change your model. For instance, if you plan not to show the Image, the model doesn't have to change. Finally, it will be easier to unit test the Model without the Forms. You can mock the data in the Model so you can show your View to others, without real data.
Quite often you need an adapter class, quite often called the ViewModel to connect the Model to the View. Together these three classes are abbreviated as MVVM. Consider to read some background information about MVVM.
Your model
So you need a class that represents your Photo. Probably something similar to this:
class Photo
{
public int Id {get; set;}
public string City {get; set;}
public string Description {get; set;}
public Image Image {get; set;}
}
Apparently you are able to store Photos somewhere, where you can retrieve them later on, even after you restarted the computer. Such a class is quite often called a Repository (a warehouse where you can store items and retrieve them later on)
interface IPhotoRepository
{
int AddP(Photo photo); // returns the Id of the added Photo
Photo Fetch(int photoId); // returns Photo with Id or null
...
}
Consider to Add functions to Update and Delete Photos. This is out of scope of your question.
You'll also need a method that has as input a string name of a city, and returns all Photos taken in this city:
IEnumerable<Photo> FetchByCity(string cityName);
Implementation of the interface:
class PhotoRepository : IPhotoRepository
{
private string ConnectionString => ...
public IEnumerable<Photo> FetchByCity(string cityName)
{
using (var dbConnection = new SqlConnection(this.ConnectionString))
{
using (var dbCommand = dbConnection.CreateCommand())
{
const string sqlText = "Select Id, Description, Image"
+ " from Photos where City = #City";
dbCommand.CommandText = sqlText;
dbCommand.Parameters.AddWithValue("#City", cityName);
dbConnection.Open();
// execute the command and return the fetched Photos:
using (var dbReader = dbCommand.ExecuteReader())
{
while (dbReader.Read())
{
// There is still a fetched row to process:
Photo fetchedPhoto = new Phto
{
Id = dbReader.GetInt64(0),
City = cityName,
Description = dbReader.GetString(1),
Image = (Image) dbReader.GetValue(2),
// I'm not not sure how to read an Image
};
yield return fetchedPhoto;
}
}
}
}
}
// TODO: implement other methods
}
In your form:
private IPhotoRepository PhotoRepository {get;} ...
// fill this in the constructor with a new PhotoRepository
private ICollection<Photo> FetchPhotosByCity(string cityName)
{
return this.PhotoRepository.FetchByCity(cityName).ToList();
}
Because you separated your Mode (= classes Photo and PhotoRepository) from your View (= your form), you are able to unit test the database access without the form. You also see that your errors have nothing to do with your form.
If you want to show your Form with some mock data, you just create a class that implements IPhotoRepository and fill it with some mock images without a database.
It is easy to see, that if you later decide to save your Photos in a file, that your form won't have to change. If you add properties to your Photo, the form won't have to change.
I just started coding with C# and SQL this week to create a desktop application; after login I want to put the user data who logged in other form # dashboard, but I couldn't find a way to do this. I found a way to create a class and put that user data in it so you can grab; but I am really stuck here.
public void bunifuFlatButton1_Click(object sender, EventArgs e)
{
SqlConnection con = new SqlConnection("Data Source=DESKTOP-R3ILNJ7;Initial Catalog=Project2;Integrated Security=True");
String query = "SELECT * FROM USERDB WHERE PRENOM='" + alphaBlendTextBox1.Text + "'AND PASS='" + alphaBlendTextBox2.Text + "'";
SqlDataAdapter sda = new SqlDataAdapter(query, con);
DataTable dtbl = new DataTable();
sda.Fill(dtbl);
if(dtbl.Rows.Count == 1)
{
string name = dtbl.Rows[0]["Nom"].ToString();
this.Hide();
Form1 f1 = new Form1();
f1.ShowDialog();
}
else
MessageBox.Show("mauvais password try again");
}
Modify the constructor of Form1 and when creating object of Form1 also pass the value which you can use in your Form1. Below is sample code of your Form1:
namespace YourNameSpace
{
public partial class Form1 : Form
{
DataTable MyDataTable = new DataTable();
public Form1(DataTable _MyDataTable)
{
InitializeComponent();
MyDataTable = _MyDataTable;
}
}
}
Then change your code to pass your values to this form like below:
if(dtbl.Rows.Count == 1)
{
string name = dtbl.Rows[0]["Nom"].ToString();
this.Hide();
Form1 f1 = new Form1(dtbl);
f1.ShowDialog();
}
else
MessageBox.Show("mauvais password try again");
One way of doing this is to create an Object which contains the data you read from your DB and then pass this into the constructor of your new form.
//This class will store the data from the DB
public class MyClass
{
Public string Name { get; set; }
//Repeat for all fields retrieved from the DB that you require.
public MyClass()
{
}
}
//I changed below to have Using clauses. The way you had it you were not correctly disposing your objects and disconnecting from the DB,
//and you would have memory leaks and other problems later
DataTable dtbl = new DataTable();
using (SqlConnection con = new SqlConnection("Data Source=DESKTOP-R3ILNJ7;Initial Catalog=Project2;Integrated Security=True"))
{
//I Changed this to use Parameters!
//See https://www.dreamincode.net/forums/topic/268104-the-right-way-to-query-a-database-parameterizing-your-sql-queries/
String query = "SELECT * FROM USERDB WHERE PRENOM= #PRENOM AND PASS= #PASS";
using (SqlCommand command = new SqlCommand(query, con))
{
using (SqlDataAdapter sda = new SqlDataAdapter(command))
{
//Check the SQLDbType below is correct for you DB schema!
sda.SelectCommand.Parameters.Add("#PRENOM", SqlDbType.NVarChar).Value = alphaBlendTextBox1.Text;
sda.SelectCommand.Parameters.Add("#PASS", SqlDbType.NVarChar).Value = alphaBlendTextBox2.Text;
sda.Fill(dtbl);
}
}
}
//Declare your class here
MyClass mc = new MyClass();
if(dtbl.Rows.Count == 1)
{
mc.Name = dtbl.Rows[0]["Nom"].ToString();
Form1 f1 = new Form1(mc);
this.Hide();
f1.ShowDialog();
}
else
MessageBox.Show("mauvais password try again");
dtbl = null;
//Now update your Form code and create a new constructor
public partial class Form1 : Form
{
//This is where you will store the incoming data
private MyClass IncomingMyClass { get; set; }
//Change the existing constructor to Private
private Form1()
{
InitializeComponent();
}
//Create a new constructor, which calls the empty (now private) constructor above
public Form1(MyClass myclass): this()
{
this.IncomingMyClass = myclass;
}
....
I am creating an airline booking system and I have 2 combo boxes. The first is for Departure City and the second is for Arrival City. I want to be able to eliminate the choice in the first combo box from the second, as I don't want the same city to be able to be submitted as both the departure and arrival city. I am querying the city names from a database.
Here is my code:
public partial class main : Form
{
public main()
{
InitializeComponent();
string connectionString = #"Base Schema Name=cyanair;data source=C:\Users\Client 0819\source\repos\Cyanair\cyanair.db";
//Departure ComboBox
SQLiteConnection conn = new SQLiteConnection(connectionString);
try
{
conn.Open();
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT * FROM CyanairAirports";
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
comboDeparture.DataSource = dt;
comboDeparture.ValueMember = "Descriptions";
comboDeparture.DisplayMember = "Descriptions";
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//Arrival ComboBox
private void comboDeparture_DisplayMemberChanged(object sender, EventArgs e)
{
string connectionString = #"Base Schema Name=cyanair;data source=C:\Users\Client 0819\source\repos\Cyanair\cyanair.db";
SQLiteConnection conn = new SQLiteConnection(connectionString);
**String city = comboDeparture.DisplayMember;**
try
{
conn.Open();
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = conn;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText = "SELECT * FROM CyanairAirports WHERE Descriptions IS NOT '" + comboDeparture.SelectedValue.ToString() + "'";
richTextBox1.Text = "SELECT * FROM CyanairAirports WHERE Descriptions IS NOT '" + comboDeparture.SelectedValue + "'";
SQLiteDataAdapter da = new SQLiteDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
comboArrival.DataSource = dt;
comboArrival.ValueMember = "Descriptions";
comboArrival.DisplayMember = "Descriptions";
conn.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks :)
It looks like you're handling the DisplayMemberChanged event on comboDeparture, and trying to update the values of comboArrival in that handler. However, DisplayMemberChanged only triggers when the DisplayMember property changes.
DisplayMember only tells the control which property to display on a data bound control. It isn't tied to the index or value selected in the ComboBox. So, the only time the code to populate comboArrival runs is in the constructor when you set comboDepartarture.DisplayMember. Instead, handle either ComboBox.SelectedIndexChanged or ComboBox.SelectedValueChanged and set the items of comboArrival.
A few other important things to note about your code.
First, you should use a parameterized query when running Sql Statements, rather than concatenating strings. Concatenating strings as you're doing opens you up to SQL Injection Attacks. I'm not familiar with SqlLite and can't provide you with an example of how to modify your code, but perhaps this question can help.
Second, you don't need to re-run the query every time you change the selected value in comboDeparture. Just add comboArrival's data source as a field on the Form and you can filter it. For example...
public partial class main : Form
{
// Your constructors...
private void comboDepartures_SelectedIndexChanged(object sender, EventArgs e)
{
if (_arrivalsDataSource == null)
{
_arrivalsDataSource = new System.Data.DataTable();
// Load _arrivalsDataSource from the database, basically how you're doing it now.
comboArrival.DataSource = _arrivalsDataSource.DefaultView;
comboArrival.DisplayMember = "Descriptions"
comboArribal.ValueMember = "Descriptions"
}
if (comboDeparture.SelectedIndex == -1)
{
_arrivalsDataSource.DefaultView.RowFilter = null; // Clear the filter.
}
else
{
// Set the filter.
_arrivalsDataSource.DefaultView.RowFilter = $"Description <> '{comboDeparture.SelectedValue}'";
}
}
private System.Data.DataTable _arrivalsDataSource = null;
}
I have a Textbox with which I want to be able to Search and Insert data into Table. Insert works fine with one exception: When I try to Insert data that isn't already in DB(it's searching while I'm typing) it gives me:
"Exception User-Unhandled System.NullReferenceException: 'Object
reference not set to an instance of an object.'
System.Windows.Forms.DataGridView.CurrentRow.get returned null.
I think I'm missing something in the Search code.
//UPDATE: All of the code.// This is my Insert and Search code:
namespace UDDKT
{
public partial class FrmGlavna : Form
{
DataSet ds = new DataSet();
SqlDataAdapter DaDavaoci = new SqlDataAdapter();
SqlDataAdapter DaAkcije = new SqlDataAdapter();
SqlConnection cs = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\UDDKT.mdf;Integrated Security=True");
public FrmGlavna()
{
InitializeComponent();
}
//Popunjava DataGridViews sa podacima iz baze
private void FrmGlavna_Load(object sender, EventArgs e)
{
SqlCommand SlctDavaoci = new SqlCommand("SELECT * FROM Davaoci ORDER BY DavaocID DESC", cs);
DaDavaoci.SelectCommand = SlctDavaoci;
DaDavaoci.Fill(ds, "TblDavaoci");
SqlCommand SlctAkcije = new SqlCommand("SELECT * FROM AkcijaDDK", cs);
DaAkcije.SelectCommand = SlctAkcije;
DaAkcije.Fill(ds, "TblAkcije");
DgDavaoci.DataSource = ds.Tables["TblDavaoci"];
}
//Povezuje DataGridViews Davaoca i Akcija
private void DgDavaoci_SelectionChanged(object sender, EventArgs e)
{
ds.Tables["TblAkcije"].DefaultView.RowFilter = "DavaocID =" + DgDavaoci.CurrentRow.Cells["DavaocID"].Value;
DgAkcije.DataSource = ds.Tables["TblAkcije"];
}
//Osvježava DataGridView nakon unosa/izmjene/brisanja podataka u bazu
private void RefreshTable()
{
SqlConnection cs = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\UDDKT.mdf;Integrated Security=True");
String query = "SELECT * FROM Davaoci ORDER BY DavaocID DESC";
SqlCommand cmd = new SqlCommand(query, cs);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);
DgDavaoci.DataSource = dt;
}
//Čisti TextBox nakon upisa/izmjene/brisanja podataka u bazu
public void ClearTxtBx()
{
TxtIme.Clear();
TxtPrezime.Clear();
TxtTezina.Clear();
TxtAdresa.Clear();
TxtBrojTel.Clear();
TxtBrojLK.Clear();
}
//Upis podataka u Tabelu Davaoci
private void BtnDodajDavaoca_Click(object sender, EventArgs e)
{
String query = "INSERT INTO Davaoci (Ime,Prezime,Pol,DatumRodjenja,KrvnaGrupa,Tezina,Adresa,BrojTel,BrojLK) VALUES (#Ime, #Prezime, #Pol, #DatumRodjenja, #KrvnaGrupa, #Tezina, #Adresa, #BrojTel, #BrojLK)";
using (SqlConnection cs = new SqlConnection(#"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\UDDKT.mdf;Integrated Security=True"))
using (SqlCommand command = new SqlCommand(query, cs))
{
command.Parameters.Add("#Ime", SqlDbType.NVarChar).Value = TxtIme.Text;
command.Parameters.Add("#Prezime", SqlDbType.NVarChar).Value = TxtPrezime.Text;
command.Parameters.Add("#Pol", SqlDbType.NChar).Value = TxtPol.Text;
command.Parameters.Add("#DatumRodjenja", SqlDbType.Date).Value = TxtDatumRodjenja.Text;
command.Parameters.Add("#KrvnaGrupa", SqlDbType.VarChar).Value = TxtKrvnaGrupa.Text;
command.Parameters.Add("#Tezina", SqlDbType.Float).Value = TxtTezina.Text;
command.Parameters.Add("#Adresa", SqlDbType.NVarChar).Value = TxtAdresa.Text;
command.Parameters.Add("#BrojTel", SqlDbType.NVarChar).Value = TxtBrojTel.Text;
command.Parameters.Add("#BrojLK", SqlDbType.NVarChar).Value = TxtBrojLK.Text;
cs.Open();
command.ExecuteNonQuery();
cs.Close();
RefreshTable();
ClearTxtBx();
}
}
//Pretraga postojećih Davalaca
private void TxtIme_TextChanged(object sender, EventArgs e)
{
(DgDavaoci.DataSource as DataTable).DefaultView.RowFilter = string.Format("Ime LIKE '{0}%'", TxtIme.Text);
}
}
}
}
Here is the MockUp of the Form before I begin to type/search/insert Data that isn't already in the Table (First Textbox*).
And after I start typing Name(Име) that starts with an "A" (name that isn't already in the Table).
I want to Search DB for that Column, but if there aren't any existing names, I want to be able to continue typing (without interuption) so that I can Insert new data into table.
DgDavaoci.CurrentRow in your DgDavaoci_SelectionChanged method is null, so attempting to access DgDavaoci.CurrentRow.Cells["DavaocID"] throws the NullReferenceException. The reason, best I can tell, is as follows:
You begin to type a value into your text box, a value that happens not to be found in the data set. As you type, you cause the TxtIme_TextChanged method to execute. It filters according to your search, and since the value is not found, it filters out every row in the set. Here's the important part: whenever the data set is filtered, it has the possibility of causing DgDavaoci_SelectionChanged to execute. Since the selection changed from the first row to no row at all (since there are no filtered rows to display), this method does execute. Now, when the method attempts to access the current row, there is no current row, and so we get a null here. Attempting to access a field of null throws the exception you're getting.
How can you fix this behavior? A simple null-check in DgDavaoci_SelectionChanged should do the trick. It looks to me like you can simply return from that method if(DgDavaoci.CurrentRow == null), or you can code in additional behavior. Just perform a check so that you don't reference the null object.
Probably the filter inside TxtIme_TextChanged is causing the DataGridView's SelectionChanged event to fire and the code is entering DgDavaoci_SelectionChanged. The exception indicates that DgDavaoci.CurrentRow is null, so you'll need to handle the case where DgDavaoci.CurrentRow is null in DgDavaoci_SelectionChanged.
A simple way to deal with this would be to just check DgDavaoci.CurrentRow is null and return from the function if that evaluates to true.
private void DgDavaoci_SelectionChanged(object sender, EventArgs e)
{
if (DgDavaoci.CurrentRow is null)
{
return;
}
ds.Tables["TblAkcije"].DefaultView.RowFilter = "DavaocID =" +
DgDavaoci.CurrentRow.Cells["DavaocID"].Value;
DgAkcije.DataSource = ds.Tables["TblAkcije"];
}
It looks like you might have a second DataGridView (DgAkcije) that is designed to show the details of the currently selected row in DgDavaoci. So, another approach might be to just clear DgAkcije if DgDavaoci.CurrentRow is null.
private void DgDavaoci_SelectionChanged(object sender, EventArgs e)
{
if (DgDavaoci.CurrentRow is null)
{
DgAkcije.DataSource = null; //I'm not 100% sure this will work, I haven't tested it.
return;
}
ds.Tables["TblAkcije"].DefaultView.RowFilter = "DavaocID =" +
DgDavaoci.CurrentRow.Cells["DavaocID"].Value;
DgAkcije.DataSource = ds.Tables["TblAkcije"];
}
Ultimately, however, you'll have to decide what you want to happen when DgDavaoci_SelectionChanged is called but DgDavaoci.CurrentRow is null.
Solution if anyone else is interested:
//Povezuje DataGridViews Davaoca i Akcija
private void DgDavaoci_SelectionChanged(object sender, EventArgs e)
{
if (DgDavaoci.CurrentRow != null)
{
ds.Tables["TblAkcije"].DefaultView.RowFilter = "DavaocID =" + DgDavaoci.CurrentRow.Cells["DavaocID"].Value;
DgAkcije.DataSource = ds.Tables["TblAkcije"];
}
}
I have a drop down list on one form that populates a puzzle id code from a sql table.
when the user selects a puzzle code say "puzzle2" i want the next form(play:Form) to display this puzzle. At the moment i can only get it to display the 1st puzzle "puzzle1" on the page.
The database consists of puzzleID which is the puzzle type and puzzle which is the puzzle question itself.
public partial class Play : Form
{
public Play()
{
InitializeComponent();
SqlConnection conn = new SqlConnection("Data Source=LAURA-PC;Initial Catalog=Sudoku;Integrated Security=True");
conn.Open();
SqlCommand command = conn.CreateCommand();
command.CommandText = "Select puzzle from Puzzle";
command.CommandType = CommandType.Text;
SqlDataReader reader = command.ExecuteReader();
if (reader.Read())
{
string[] tokens = ((string)reader[0]).Split(';');
textBox1.Text = tokens[0];
textBox2.Text = tokens[1];
textBox3.Text = tokens[2];
textBox4.Text = tokens[3];
textBox5.Text = tokens[4];
textBox6.Text = tokens[5];
textBox7.Text = tokens[6];
textBox8.Text = tokens[7];
textBox9.Text = tokens[8];
textBox10.Text = tokens[9];
textBox11.Text = tokens[10];
textBox12.Text = tokens[11];
textBox13.Text = tokens[12];
textBox14.Text = tokens[13];
textBox15.Text = tokens[14];
textBox16.Text = tokens[15];
}
conn.Close();
}
I know i need to implement some sort of of global variable from the drop down list in the previous form and then try filter that variable into Where statement? But im having no luck.
Thanks
You can make an static class as a common place to share objects. All classes can see this class and use its members.
public static class CommonClass
{
public static String puzzleCode ;
}
Also you can have a property on the second form to accept the puzzle id. Like this :
public class SecondForm : Form
{
private String _puzzleId ;
public String PuzzleId
{
get { return _puzzleId ; }
set { _puzzleId = value ; }
}
}
1. Passing variable to form.
Play frmPlay = new Play(puzzleId);
frmPlay.Show();
your Play class will be changed by this
public Play(int puzzleId)
{
//Unchanged code
command.CommandText = "Select puzzle from Puzzle where puzzleId = "+puzzleId;
//Unchanged code
}
2. Passing data through delegate
Add a delegate signature to form1 as below:
public delegate void delPassData(int puzzleId);
Play frmPlay= new Play ();
delPassData del=new delPassData(frmPlay.SetPuzzleId);
del( Convert.ToInt32(cmBxPuzzleId.SelectedValue));
frmPlay.Show();
**In Play form write this code**
private int m_PuzzleId;
public void SetPuzzleId(int puzzleId )
{
m_PuzzleId = puzzuleId;
}