Refresh button duplicate the datagridview data - c#

I have problem when i try to refresh data in datagridview. Am using MySQL database. On every click on Reload button my old data is duplicated in grid. I try to set datagridview.DataSource = null also try to Refresh datagrid and also try to Resert binding source but nothing is happening.
Check this:
public MainForm()
{
InitializeComponent();
this.connStr = Properties.Settings.Default.connStr;
}
// Load
private void Form1_Load(object sender, EventArgs e)
{
SelectData();
}
// Seslect Data
public void SelectData()
{
bs.DataSource = GetData("SELECT * FROM porudzbine");
dataGridView1.DataSource = bs;
}
// Get Data
private DataTable GetData(string query)
{
try
{
conn = new MySqlConnection(connStr);
conn.Open();
adapter = new MySqlDataAdapter(query, conn);
adapter.Fill(dt);
}
catch(MySqlException ex)
{
MessageBox.Show(ex.Message.ToString());
}
return dt;
}
// Reload
private void osveziListuPorudzbinaButton_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = null;
dataGridView1.Refresh();
bs.ResetBindings(false);
bs.DataSource = GetData("SELECT * FROM porudzbine");
dataGridView1.DataSource = bs;
}

You have a field called dt somewhere in your form (not shown in the post), which you are refilling (hence adding the records to the previously loaded records) on each GetData call.
Remove the field and use something like this:
// Get Data
private DataTable GetData(string query)
{
var dt = new DataTable();
// ...
return dt;
}

Related

listbox error: Items collection cannot be modified when the DataSource property is set

I have 2 listboxes in a window form, one on left and one on right. The
1st listbox have some items while the 2nd listbox is empty. Also there
are 2 buttons between the 2 listboxes which used to move item from/to
the 1st and 2nd listbox
My problem here is that after I bind the data to the 1st listbox (from
a database, using DisplayMember and ValueMember) , and I try to move 1
of the item from this 1st listbox to the 2nd listbox and I want that
the selected item is also removed from the 1st listbox by:
private void btnMoveRight_Click(object sender, EventArgs e)
{
ADD();
}
private void ADD()
{
int c = listJobBox.Items.Count - 1;
` for(int i= c; i>=0; i--)
{
if(listJobBox.GetSelected(i))
{
lstAssignedJobs.Items.Add(listJobBox.Items[i]);
listJobBox.Items.Remove(listJobBox.SelectedItem); ---error line
But the selected item is not removed from the 1st listbox.
it displays error message "Items collection cannot be modified
when the DataSource property is set."
can any one give me the solution to my problem.
Add a boolean column to your DataTable object, something like IsSelected.
Then instead of binding your listbox1 directly to the table, bind it to a BindingSource. Add 2 bindingsources to your form using the designer. And place this code in your code behind file.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.InitializeDataObjects();
}
private void InitializeDataObjects()
{
this.InitData();
this.InitBindingSources();
}
private void InitData()
{
ds = new DataSet();
var dt = new DataTable("Table1");
dt.Columns.Add("Name", typeof(string));
ds.Tables.Add(dt);
}
private void InitBindingSources()
{
bindingSource1 = new BindingSource();
bindingSource2 = new BindingSource();
bindingSource1.DataSource = ds;
bindingSource1.DataMember = "Table1";
bindingSource2.DataSource = ds;
bindingSource2.DataMember = "Table1";
listBox1.DataSource = bindingSource1;
listBox1.DisplayMember = "Name";
listBox2.DataSource = bindingSource2;
listBox2.DisplayMember = "Name";
}
}
Then when you load your data, do the following:
private void btnLoadAndBind_Click(object sender, EventArgs e)
{
this.FetchData(this.ds.Tables["Table1"]);
this.AddSelectedColumn(this.ds.Tables["Table1"]);
this.bindingSource1.Filter = "IsSelected = false";
this.bindingSource2.Filter = "IsSelected = true";
}
private void FetchData(DataTable dataTable)
{
string CS = "your connectionstring";
using (SqlConnection con = new SqlConnection(CS))
{
try
{
SqlDataAdapter da = new SqlDataAdapter();
con.Open();
var sqlcmd = new SqlCommand("SELECT Name FROM sometable", con);
sqlcmd.CommandType = CommandType.Text;
da.SelectCommand = sqlcmd;
da.Fill(dataTable);
}
catch (Exception ex)
{
MessageBox.Show("exception raised");
throw ex;
}
}
}
private void AddSelectedColumn(DataTable suppliersDataTable)
{
var dc = new DataColumn("IsSelected", typeof(bool));
suppliersDataTable.Columns.Add(dc);
foreach (DataRow dr in suppliersDataTable.Rows)
{
dr["IsSelected"] = false;
}
}
Now your listboxes are both connected to the same datatable and filtered based on the IsSelected property / column. Just set this column to true or false and it will flip from box to box. Your eventhandler of a button could look like this:
public void button_Click(object sender, EventArgs e)
{
if (this.bindingSource1.Current!= null)
{
var dr = ((DataRowView)this.bindingSource1.Current).Row;
dr["IsSelected"] = true;
}
}
This works!
Things will be become much simpeler if you use a typed dataset. Most of the bindings then can be done in the designer and your code behind will shrink to 20 lines of code....
Lets say listbox1 is bound to datatable1 (it could be any other collection type) and listbox2 is bound to datatable2. When you click on move button, remove the selected item from the collection i.e datatable1 and add that item to other collection i.e. datatable2 and re-bind the listbox1 and lisbox2.
Here is a rough working example:
public partial class Form1 : Form
{
private DataTable _dataSource1;
private DataTable _dataSource2;
public Form1()
{
InitializeComponent();
_dataSource1 = GetData1();
_dataSource2 = GetData2();
Initialize();
}
private void btnMove_Click(object sender, EventArgs e)
{
MoveItem();
}
void Initialize()
{
listBox1.DataSource = _dataSource1;
listBox1.DisplayMember = "Fruits";
listBox1.ValueMember = "Fruits";
listBox2.DataSource = _dataSource2;
listBox2.DisplayMember = "Fruits";
listBox2.ValueMember = "Fruits";
}
DataTable GetData1()
{
var dt = new DataTable();
dt.Columns.Add("Fruits");
dt.Rows.Add(new object[] {"Apple"});
dt.Rows.Add(new object[] { "Orange" });
dt.Rows.Add(new object[] { "Grapes" });
return dt;
}
DataTable GetData2()
{
var dt = new DataTable();
dt.Columns.Add("Fruits");
return dt;
}
void MoveItem()
{
var index = listBox1.SelectedIndex;
var dataRowToRemove = _dataSource1.Rows[index];
var listItem = dataRowToRemove[0] as string;
_dataSource1.Rows.Remove(dataRowToRemove);
var dataRowToAdd = _dataSource2.NewRow();
dataRowToAdd[0] = listItem;
_dataSource2.Rows.Add(dataRowToAdd);
Initialize();
}
}

unable to bind data with dropdown list?

I am making an application in asp.net using C# which contains drop down list.Now I don't want to write same code for fetching same data from database.I am try this code but it's not working
protected void Page_Load(object sender, EventArgs e)
{
DataTable DT = sel_obj.select_Dept_Name();
departmentDrop.DataSource = DT;
departmentDrop.DataMember = "Department_Name";
departmentDrop.DataBind();
}
public DataTable select_Dept_Name()
{
module c = new module();
c.DB_Connection();
if (c.con.State == ConnectionState.Open)
{
c.con.Close();
c.con.Open();
}
DataSet DS = new DataSet();
string QRY = "";
QRY = "SELECT Department_Name FROM Department_Master";
SqlDataAdapter DA = new SqlDataAdapter(QRY, c.con);
DA.Fill(DS);
DataTable DT = DS.Tables[0];
return DT;
}
You need to call "DataBind()" function. You need to also make sure that your table contains data to bind with dropdown list.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable DT = sel_obj.select_Dept_Name();
departmentDrop.DataSource = DT ;
departmentDrop.DataTextField = "Department_Name";
departmentDrop.DataValueField = "Department_Name";
departmentDrop.DataBind();
}
}

Select a DataRow in a DataGridView after creating new row

I use a PostgreSQL view to display data in a DataGridView:
dataSource = new BindingSource();
dataSource.DataSource = Program.DB.GetView(dbView); // returns a DataTable
dgData.DataSource = dataSource;
Now, after I added a record using a PostgreSQL function, I refresh the data in the grid (I don't call Rows.Add() on the DataGridView:
protected void RefreshData() {
dataSource.DataSource = Program.DB.GetView(dbView);
}
The insertion function of PostgreSQL returns the ID of the inserted row, so I know the ID (which is primary key) and want to set Selected to true in the DataGridView. The row can be anywhere in the set, because the view is sorted by name, not ID. I reckon I could do that by cycling over all rows and set the Selected when I found it, but this could become slow on large datasets.
Is there a way to somehow bind the rows of the datasource to the datagrid?
Add an event handler to the ListChanged event:
dataSource.ListChanged += dataSource_ListChanged;
Here is the event handler definition:
void dataSource_ListChanged(object sender, ListChangedEventArgs e)
{
if (dgData.Rows.Count > 0)
dgData.CurrentCell = dgData.Rows[e.NewIndex].Cells[0];
}
[UPDATE]
As I also suggested in the comments, maybe you should not repopulate the data source on each insert (or update). To demonstrate my point, I'll post a code sample which uses a DataGridView, 2 TextBoxes and 2 Buttons (for insert and update) and a SqlDataAdapter. The SQL table has 2 columns (id and value).
Here's the code (I didn't cover the deletion):
public partial class Form1 : Form
{
static BindingSource dataSource;
static string dbView = "default";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dgData.MultiSelect = false;
dataSource = new BindingSource();
dataSource.ListChanged += dataSource_ListChanged;
RefreshData();
dgData.DataSource = dataSource;
dgData.Sort(dgData.Columns[1], ListSortDirection.Ascending);
}
void dataSource_ListChanged(object sender, ListChangedEventArgs e)
{
if (dgData.Rows.Count > 0)
dgData.CurrentCell = dgData.Rows[e.NewIndex].Cells[0];
}
protected void RefreshData()
{
dataSource.DataSource = DB.GetView(dbView);
}
private void insert_Click(object sender, EventArgs e)
{
DB.Insert(textBox1.Text);
RefreshData();
}
private void update_Click(object sender, EventArgs e)
{
DB.UpdateRandomRow(textBox2.Text);
RefreshData();
}
}
class DB
{
static DataTable dt;
static string conStr = "yourConnectionString";
static SqlDataAdapter _adapter;
static Random r = new Random(10);
public static SqlDataAdapter CreateSqlDataAdapter(SqlConnection connection)
{
_adapter = new SqlDataAdapter();
_adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
_adapter.SelectCommand = new SqlCommand(
"SELECT * FROM test", connection);
_adapter.InsertCommand = new SqlCommand(
"INSERT INTO test (value) " +
"VALUES (#value)", connection);
_adapter.UpdateCommand = new SqlCommand(
"UPDATE test SET [value] = #value " +
"WHERE id = #id", connection);
_adapter.InsertCommand.Parameters.Add("#value",
SqlDbType.NVarChar, 50, "value");
_adapter.UpdateCommand.Parameters.Add("#id",
SqlDbType.Int, 4, "id").SourceVersion = DataRowVersion.Current;
_adapter.UpdateCommand.Parameters.Add("#value",
SqlDbType.NVarChar, 50, "value").SourceVersion = DataRowVersion.Current;
return _adapter;
}
// random update, to demonstrate dynamic
// repositioning
public static DataTable UpdateRandomRow(string value)
{
var currentRandom = r.Next(dt.Rows.Count);
dt.Rows[currentRandom].SetField<string>(1, value);
using (var con = new SqlConnection(conStr))
{
con.Open();
_adapter = CreateSqlDataAdapter(con);
_adapter.Update(dt);
}
return dt;
}
internal static DataTable GetView(string dbView)
{
if (dt == null)
{
dt = new DataTable();
using (var con = new SqlConnection(conStr))
{
con.Open();
_adapter = CreateSqlDataAdapter(con);
_adapter.Fill(dt);
}
}
return dt;
}
internal static void Insert(string value)
{
if (dt == null)
GetView("");
var dr = dt.NewRow();
dr[1] = value;
dt.Rows.Add(dr);
using (var con = new SqlConnection(conStr))
{
con.Open();
_adapter = CreateSqlDataAdapter(con);
_adapter.Update(dt);
}
}
}
If you test it, you'll see that the request from your question is satisfied for both insert and update. Also, please note the performance improvement, as the data table is not recreated on each operation.

ResetBinding in C#

I have a function
public DataSet Select(string sql)
{
//Get data source from database to DataSet
}
in class DataDriverExample
and in form_load, I bind to the datagridview.
public BindingSource bs = new BindingSource()
public void form_load()
{
DataSource ds = DataDriverExample.Select("Select * from XYZ");
bs.DataSource = ds;
dataGridView.DataSoure = bs;
dataGridView.DataMember = "TableResult";
txtAbc.Bindings.Add("text",bs,"TableResult.Col1");
}
it worked,
but I have Button Add (which adds a new record to the database)
public void btnAdd_click()
{
DataDriverExample.Insert("Insert into XYZ values (\"Test\",\"Hello\",\"Bla\")");
DataSource ds = DataDriverExample.Select("Select * from XYZ");
bs.DataSource = ds;
bs.ResetBinding(true);
}
In my database it now has new record, but I get the error Cannot bind to the property or column on the DataSource
Sorry for my english not good.
Anyone can help me.
Tks
To Clean up your code, create another method for your binding something like:
private void LoadData()
{
bs.ResetBinding(true);
txtAbc.DataBindings.Clear()
DataSource ds = DataDriverExample.Select("Select * from XYZ");
bs.DataSource = ds;
dataGridView.DataSoure = bs;
dataGridView.DataMember = "TableResult";
txtAbc.Bindings.Add("text",bs,"TableResult.Col1");
}
Then just call LoadData(); on your formload and add method
public BindingSource bs = new BindingSource()
public void form_load()
{
LoadData();
}
Add:
public void btnAdd_click()
{
DataDriverExample.Insert("Insert into XYZ values (\"Test\",\"Hello\",\"Bla\")");
LoadData();
}
Hope this helps
Regards

Binding search results to data grid

I want to add search functionality to my program. There's a class which has this function:
public DataTable Search()
{
string SQL = "Select * from Customer where " + mField + " like '%" + mValue + "%'";
DataTable dt = new DataTable();
dt = dm.GetData(SQL);
return (dt);
}
There are setter and getter properties for mField and mValue. DM is the object of class DataManagement, which has a method GetData:
public DataTable GetData(string SQL)
{
SqlCommand command = new SqlCommand();
SqlDataAdapter dbAdapter = new SqlDataAdapter();
DataTable DataTable = new DataTable();
command.Connection = clsConnection.GetConnection();
command.CommandText = SQL;
dbAdapter.SelectCommand = command;
dbAdapter.Fill(DataTable);
return (DataTable);
}
The search functionality is currently implemented like this:
private void btnfind_Click(object sender, EventArgs e)
{
//cust is the object of class customer//
if (tbCustName.Text != "")
{
cust.Field="CustName";
cust.Value = tbCustName.Text;
}
else if (tbAddress.Text != "")
{
cust.Value = tbAddress.Text;
cust.Field="Address";
}
else if (tbEmail.Text != "")
{
cust.Value = tbEmail.Text;
cust.Field="Email";
}
else if (tbCell.Text != "")
{
cust.Value = tbCell.Text;
cust.Field = "Cell";
}
DataTable dt = new DataTable();
dt = cust.Search();
dgCustomer.DataSource = dt;
RefreshGrid();
}
private void RefreshGrid()
{
DataTable dt = new DataTable();
dt = cust.GetCustomers();
dgCustomer.DataSource = dt;
}
This is not working. I don't know why. Please help.
Add a DataBind() statement in your RefreshGrid() method to have your new results actually shown on the Grid.
private void RefreshGrid()
{
DataTable dt = cust.GetCustomers();
dgCustomer.DataSource = dt;
dgCustomer.DataBind();
}
Consider modifying your other method as well:
Your ad-hoc SQL has a SQL injection vulnerability. Stop everything until you fix that!
btnfind_Click doesn't need to end up calling cust.Search() twice.
private void btnfind_Click(object sender, EventArgs e)
{
//<snip>
// no need to do all this twice.
// DataTable dt = new DataTable();
// dt = cust.Search();
// dgCustomer.DataSource = dt;
RefreshGrid();
}
Your RefreshGrid method is overwriting the DataSource you set in btnfind_Click... don't call it, just call DataBind
private void btnfind_Click(object sender, EventArgs e)
{
...
DataTable dt = cust.Search();
dgCustomer.DataSource = dt;
dgCustomer.DataBind();
}
By the way, you don't need to assign a new DataTable to dt if you're immediately setting it to the result of cust.Search... you're just creating an instance for nothing (I fixed it in the code above)

Categories

Resources