Currently my application will load items from the SQL database that the user can select from, they can then use the checkboxes to select which of these items are applicable to themselves, then can then save these selections and exit the window; this works fine.
I need to make my application fetch the user's previously saved selection, and then check the relevant boxes once the grid has been populated with all of the options (so just showing their selection).
I have the following code so far:
private void LoadUserSelection()
{
using (SqlConnection conn = new SqlConnection(sys.gvConnectionString))
{
using (SqlCommand cmd = new SqlCommand(qry.SelectUsersSelections(), conn))
{
cmd.Parameters.AddWithValue("#SiteID", sys.gvSiteID);
using (SqlDataAdapter da = new SqlDataAdapter())
{
da.SelectCommand = cmd;
using (DataTable dt = new DataTable())
{
conn.Open();
da.Fill(dt);
conn.Close();
foreach (DataGridViewRow row in grdQueues.Rows)
{
foreach (DataRow dr in dt.Rows)
{
if (dr["ID"].ToString() == row.Cells["ID"].Value.ToString())
{
DataGridViewCheckBoxCell chk = (DataGridViewCheckBoxCell)row.Cells[0];
chk.Value = 1;
}
}
}
}
}
}
}
}
Hopefully this code make sense, it runs without issue, however even though the code does in fact hit the section to mark the checkbox as true it does not.
I have tried the following alternatives for chk.Value = 1
chk.Value = TrueValue;
chk.Selected = true;
chk.Value = true;
As this is a multi-user database, I cannot simply store boolean values against the pre-determined list, hence why the pre-determined list is fetched and populated first, and then I'm trying to action their previous selections.
Note: I'm not too sure what I'm doing above is even the best way to go around this, so as a bonus, if anyone has any tips on how I've nested the using statements or how I'm approaching this, it would be appreciated.
Your code is correct using either of the two following options:
chk.Value = 1; // Or...
chk.Value = true;
The only way I could duplicate this problem was if the DataGridViewCheckBoxColumn was manually added in the form constructor. Otherwise, when that column was also part of the original DataTable your code always worked in my tests. So assuming your workflow in that constructor is:
DataGridViewCheckBoxColumn col = new DataGridViewCheckBoxColumn();
// any col Properties manually set
dataGridView1.Columns.Add(col);
dataGridView1.AllowUserToAddRows = false;
dataGridView1.DataSource = LoadAllData();
LoadUserSelection();
You will see that LoadUserSelection correctly runs as expected, but due to binding behavior during construction you are not seeing the results. If you were to call your method anywhere else (like a Button.Click event) you'd probably see the results. If you want this behavior once the data is loaded, the following worked for me:
this.dataGridView1.DataBindingComplete += DataGridView1_DataBindingComplete;
private void DataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
this.LoadUserSelection();
}
Related
the following code works but the code I wrote to select all does not work. does not give any error. this code is not working ( dataGridView2.SelectAll(); )
using System.data;
private void CaO()
{
DataTable tbl = new System.Data.DataTable();
new OleDbDataAdapter("SELECT * FROM [Sayfa1$]", #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\ikinciexcel.xlsx; Extended Properties='Excel 12.0 xml;HDR=YES;'")
.Fill(tbl);
DataTable dtCloned = tbl.Clone();
dtCloned.Columns[1].DataType = typeof(float);
foreach (DataRow row in tbl.Rows)
{
dtCloned.ImportRow(row);
}
var f = new Form();
var dgv = new DataGridView
{
DataSource = dtCloned,
Dock = DockStyle.Fill,
SelectionMode = DataGridViewSelectionMode.FullRowSelect
};
dtCloned.DefaultView.RowFilter = "CaO >= 9 and CaO <= 11";
dataGridView2.Controls.Add(dgv);
dataGridView2.SelectAll();
}
Your SelectAll() method works fine, but You can't see it on the DataGridView object becuase you are calling it from place, where DataSource property is binded and selection can't be drawed. First of all change dataGridView2.SelectAll(); to dgv.SelectAll(); just like #NineBerry mentioned in comment (datasource is binded to dgv). For test please place this line of code just below dgv.SelectAll(); and place breakpoint (F9) on it:
var selectionTest = dgv.SelectedCells;
Code execution will stop on breakpoint and after pressing F10 VS will step to another line. Right click on selectionTest object and choose "Quick Watch" option. In appeared window you can watch all selected cells in proper collection object structure.
If you want to draw selection on your grid, please add some button to your form and call dgv.SelectAll(); in it's event mthod. Sample code:
private void btnSelectAll_Click(object sender, EventArgs e)
{
dgv.SelectAll();
}
This calling will draw selection on the dgv as well.
Conclusion: your code works fine, but you can be a little confused because no selection visual effect is visible as should be when row/cell is selected. Just call it from other place when binding and all other creating operations are completed.
Make sure that MultiSelect of dataGridView2 is set to true:
dataGridView2.MultiSelect = true;
I want to edit multiple cells in DataGrid, and when btnUpdate is clicked the cells I edited will be updated in database.
I have tried the ff code for btnUpdate:
DialogResult res = MessageBox.Show("Are you sure you want to apply changes?", "Confirm", MessageBoxButtons.YesNo);
if (res == DialogResult.Yes)
{
foreach (DataGridViewRow row in dgMain.SelectedRows)
{
DataTable d = dgMain.DataSource as DataTable;
long attendanceid = Convert.ToInt64(row.Cells["Attendance_Id"].Value.ToString());
EmployeeAttendance a = new EmployeeAttendance();
a.ProcAccountingAttendance_Update(attendanceid);
}
MessageBox.Show("Changes Successfully Saved!");
}
But the problem is it still doesnt Update the database.
First problem is you are going through selectedRows only which means if you changed multiple values and after all that you select only one row, only that one will be updated.
Next problem is that you are going through all selected rows, the ones with change and ones without it.
What I would do in your place is this:
Create public class like this:
class:
public class ChangedData
{
public Object primaryKey;
public Object columnName;
public Object columnValue;
}
Create public List<ChangedData> changedData; inside your form
Call cellValidating event and inside it check if old and new values are different, if they are different then do changedData.Add(new ChangedData { primaryKey = primaryKeyOfYourTable, columnName = dataGridView1.Columns[e.ColumnIndex].Name, columnValue.FormattedValue });
And finally when you press update button you go
this:
using(SqlConnection con...)
{
con.Open();
using(SqlCommand cmd = new SqlCommand("UPDATE YOURTABLE SET #ColumnName = #ColumnValue where PrimaryKeyColumn = #PrimaryKey", con);
{
cmd.Parameters.Add("#ColumnName");
cmd.Parameters.Add("#ColumnValue");
cmd.Parameters.Add("#PrimaryKey");
foreach(ChangedData cd in changedData)
{
cmd.Parameters["#ColumnName"].Value = cd.columnName.ToString();
cmd.Parameters["#ColumnValue"].Value = cd.columnValue.ToString();
cmd.Parameters["#PrimaryKey"].Value = cd.primaryKey.ToString();
cmd.ExecuteNonQuery();
}
}
con.Close();
}
Code I wrote is not tested and need editing since you haven't provided us with any code you have or structure of your database. If you need something else edit answer or comment.
UPDATE: I have finally solved the problem with the ff code:
BTW, I am using a stored procedure for my database
private void dgMain_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
string id = dgMain.Rows[e.RowIndex].Cells["Attendance_Id"].Value.ToString();
string columnname = dgMain.Columns[e.ColumnIndex].Name;
string value = dgMain.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
EmployeeAttendance a = new EmployeeAttendance();
a.ProcAccountingAttendance_UpdateByGroupIdDateFromTo(Convert.ToInt64(id),columnname,value);
}
Edit 2: Turns out it only gives a NullReferenceException the first time. After that, it says that I am not allowed to change the ConnectionString property, even though I think I have closed it in the right places.
Thanks for taking the time to read this.
I am working on a WinForms application that uses an MS Access database, and I am currently having problems with an entry deletion feature I made.
So, I have a DataGridView that switches between 3 tables on a button click, and I have a function that deletes a row on a table that is currently open by clicking a button that is at the end of the row.
When I open my first table, and try to delete a row, it works just fine. However, if I open a different table afterwards and try to delete an entry, or even go back to the first table I opened, I get a NullReferenceException in the deletion function.
Here is the code to display one of the tables in DataGridView.
public DataTable Read()
{
connection.ConnectionString = connectionString;
OpenConnection(); //connection.Open() inside an if statement
dataTable.Clear();
OleDbCommand readStudentCommand = new OleDbCommand("select * from Students", connection); //display the whole list of students
OleDbDataReader reader = readStudentCommand.ExecuteReader();
dataTable.Load(reader);
connection.Close();
return dataTable;
}
Here is the code that deletes an entry
private void MainDataGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
connection.ConnectionString = connectionString;
if (ConnectionState.Closed == connection.State)
{
connection.Open();
}
var senderGrid = (DataGridView)sender;
if (e.RowIndex >= 0 && senderGrid.Columns[e.ColumnIndex] == MainDataGridView.Columns["Delete"])
{
//this function retrieves the first column value of the deleted row, which has the ID of the entry (works with any table).
DeleteEntry(MainDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString()); //exception thrown here (System.Windows.Forms.DataGridViewCell.Value.get returned null)
MainDataGridView.Rows.RemoveAt(e.RowIndex);
}
and here is DeleteEntry()
private void DeleteEntry(string deletedID)
{
string tableName = null;
string idType = null;
if (studentsDisplayed)
{
tableName = "Students";
idType = "Student ID";
}
else if(booksDisplayed)
{
tableName = "Books";
idType = "BookID";
}
else if(loansDisplayed)
{
tableName = "Loans";
idType = "Loan ID";
}
string deleteCommand = String.Format("DELETE * FROM {0} WHERE [{1}] = {2}", tableName, idType, deletedID);
OleDbCommand deleteEntryCommand = new OleDbCommand(deleteCommand, connection);
deleteEntryCommand.ExecuteNonQuery();
SaveData(); //this method just calls Update() in a dataAdapter of a relevant table
connection.Close();
}
Thank you!
Edit:
As per request, here is the code that switches the table. It simply references the first function and sets the returned dataTable as DataSource.
private void StudentButton_Click(object sender, EventArgs e) //display students
{
try
{
if (!studentsDisplayed)
{
MainDataGridView.DataSource = studentDAL.Read(); //studentDAL is the class that works with the Students table of my DB.
studentsDisplayed = true; //these 3 are to avoid duplicated creation of the same table
booksDisplayed = false;
loansDisplayed = false;
ComboBoxChanger(); //don't mind this, it's for an irrelevant feature
CreateButtons(5);
}
}
catch
{
throw;
}
}
Okay, so turns out the problem was the fact that DeleteEntry(MainDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString()) had a problem with the Cells[0] part. After the first time loading a table, the 0th cell just vanished. So, I rewrote the code so that instead of declaring tableName and idType in DeleteEntry(), they're declared in MainDataGridView_CellContentClick(), and then made the DeleteEntry() accept 3 idType and tableName as parameters, and changed the MainDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString() argument to MainDataGridView.Rows[e.RowIndex].Cells[idType].Value.ToString(). Now it works just fine!
I'm stuck with something and I'd appreciate it if anyone can assist me.
I have a simple MS Access database that's linked to my program. The first thing I did was fill a combobox with one of the fields in my database ("Product Description").
What I'd like to do is when a user selects an item in the combobox, all the other fields in the record be displayed in text boxes.
string sConnection;
sConnection = "Provider=Microsoft.ACE.OLEDB.12.0;" +
"Data Source=XYZDatabase.accdb";
OleDbConnection dbConn;
dbConn = new OleDbConnection(sConnection);
dbConn.Open();
cbxProducts.DisplayMember = "Product Description";
dbConn.Close();
I've considered using possibly SQL or a DataReader, though I'm really not sure.
This is the event where I want the textboxes to be filled. I'm literally stuck here.
private void cbxProducts_SelectedIndexChanged(object sender, EventArgs e)
{
txtProductNumber.Text =
txtProductDescription.Text =
txtProductCategory.Text =
txtProductCost.Text =
}
I hope I haven't formatted my question wrong or anything, apologies if I have, this is my first time posting here! Dx
I wonder if your combo box is actually showing data from the DB.
In the first code block after
dbConn.Open()
and before
dbConn.Close()
you should have code like this:
SqlCommand sc = new SqlCommand("select prodid, proddesc from products", conn);
SqlDataReader reader;
reader = sc.ExecuteReader();
DataTable dt = new DataTable();
dt.Columns.Add("prodid", typeof(string));
dt.Columns.Add("proddesc", typeof(string));
dt.Load(reader);
cbxProducts.ValueMember = "prodid";
cbxProducts.DisplayMember = "proddesc";
cbxProducts.DataSource = dt;
And then in the second code block you need to fetch the selected Product ID first.
private void cbxProducts_SelectedIndexChanged(object sender, EventArgs e)
{
string ID = comboBox1.SelectedValue.ToString();
//Based on ID make a sql query and fetch the details of that product from the DB.
//Follow the earlier code block to make DB connection and execute query.
//Then populate the data in individual text boxes by looping through the dr.
//I am leaving this deliberately for you to figure out and I am sure you can.
txtProductNumber.Text =
txtProductDescription.Text =
txtProductCategory.Text =
txtProductCost.Text =
}
I've got a ComboBox on a winforms app with this code:
comboBox1.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
comboBox1.AutoCompleteSource = AutoCompleteSource.ListItems;
DataTable t = new DataTable();
t.Columns.Add("ID", typeof(int));
t.Columns.Add("Display", typeof(string));
for (int i = 1; i < 2000; i++)
{
t.Rows.Add(i, i.ToString("N0"));
}
comboBox1.DataSource = t;
comboBox1.ValueMember = "ID";
comboBox1.DisplayMember = "Display";
I then follow these steps when the window opens:
Click the ComboBox drop down button -- this displays the list of items and selects the text in the ComboBox
Type '5', '1' ... i.e. I'm looking to use autocomplete to search for 515, 516, etc.
You'll see that the autocomplete window now appears ON TOP of the drop down list. However if I mouse over, it's the obscured drop down window behind the autocomplete window that's receiving the mouse events, including the click. So I think I'm clicking on an autocomplete item but actually clicking on something totally random that I can't see.
Is this a bug in the ComboBox? I'm using Windows 7 if that matters. Am I configuring the ComboBoxwrong somehow?
Note also that using the KEYBOARD uses the autocomplete drop down. So up/down arrow keys are using the front window, but the mouse is using the back window.
Add a single line of code to your ComboBox KeyDown event and the problem is solved!
private void comboBox_NameAndID_KeyDown(object sender, KeyEventArgs e)
{
comboBox_NameAndID.DroppedDown = false;
}
Source
No problem getting a repro for this simply by setting the properties from the PropertyGrid. Behaves this way both in Win7 and Windows XP.
This is broken behavior documented in this feedback article. As indicated, Microsoft is not considering a fix. One possible workaround is to disable autocomplete in a DropDown event handler and re-enable it in a DropDownClosed event handler.
I'm a Brasilian student of encoding and I lose many hours seeking to fix it im my project. And here, I saw it in a few seconds!!!
My code seems like this:
private void populateCombos()
{
persist.ShowLst(dspMember, vlMember,varTable,lstBox,varWhere);
persist.ShowLst(dspMember, vlMember,varTable,ddlist1,varWhere);
persist.ShowLst(dspMember, vlMember,varTable, ddlist2,varWhere);
ddList1.Text = null;
ddList2.Text = null;
lstBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
lstBox.AutoCompleteSource = AutoCompleteSource.ListItems;
lstBox.Text = null;
}
Add to the/a keypress event.
Dim box As ComboBox = sender
box.DroppedDown = False
Select the ComboBox from the design view and set "Append" to the AutoCompleteMode property, this will suggest the item without apearing a window.
That's weired. Your code looks fine to me and I used this the AutoComplete feature a several times and it didn't show both the DropDown and the AutoComplete list.
My suggestion would be
Set the DataSource after the Display/Value Members. I can't remember why but the other caused some problems.
comboBox1.ValueMember = "ID";
comboBox1.DisplayMember = "Display";
comboBox1.DataSource = t;
Set the AutoCompleteSource at the end of your code (after adding the DataSouce)
Maybe that helps.
to only have one open at a time you can use comboBox1.Droppeddown = true open up the regular, false the AutoComplete will only appear
You simply add item in collection.
Now go properties option of combo box choose
AutoCompleteSource=ListItems
AutocompleteMode=suggest
note: autocomplete source have many option as per your requirement :)
WinForms ComboBox DropDown...the answer is this...
write below code in comboBox1 Enter event..
private void comboBox1_Enter(object sender, EventArgs e)
{
comboBox1.DroppedDown = true;
}
Now for comboBox1 AutoComplete...
write this AutoComplete() in page load event..so it work...
public void AutoComplete()
{
try
{
MySqlConnection conn = new
MySqlConnection("server=localhost;database=databasename;user
id=root;password=;charset=utf8;");
MySqlCommand cmd = new MySqlCommand("select distinct
(columnName) from tablename", conn);
DataSet ds = new DataSet();
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
da.Fill(ds, "tablename");
AutoCompleteStringCollection col = new
AutoCompleteStringCollection();
int i = 0;
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
col.Add(ds.Tables[0].Rows[i]["columnName"].ToString());
}
comboBox1.AutoCompleteSource = AutoCompleteSource.CustomSource;
comboBox1.AutoCompleteCustomSource = col;
comboBox1.AutoCompleteMode = AutoCompleteMode.Suggest;
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
Select the ComboBox from the design view and set "None" to the AutoCompleteMode property.