c# clear datagridview bound to datasource - c#

I have a datagridview bound to a datasource, all headers are added to the columns collection with a datapropertyname set.
When I clear the datagridview using
DataGridView1.DataSource = null;
The headers disappear also and when I fill the datagridview again the header texts are the database column names. How do I clear a bound datagridview without removing the headers?

You can use this
if (dataGridViewNotas.DataSource != null)
((DataTable) dataGridViewNotas.DataSource).Rows.Clear();

One of the approach to handle this issue is to use collection as data source,
Create a class with properties representing the data source (Each property would represent a column in the database)
public class Student
{
public string Name { get; set; }
public string Address { get; set; }
}
You need Add column to datagridview manually and set relevant DataPropertyName for each column and set the HeaderText. When you load the data from database first fill this data into a List. So you will have a List<Student>.
List<Student> studentDetail = new List<Student>();
Set this as the data source of the datagridview.
dataGridView1.DataSource = studentDetail;
Clearing Data source
To clear the data source of the Grid just create a empty Student list and set it as data source again. When you set like this header of each column will be retained.
List<Student> emptyStudentDetail = new List<Student>();
dataGridView1.DataSource = emptyStudentDetail;

If you do not want to use collection of objects and still refresh your data source using this.dataGridView1.DataSource = null; then try this approach:
Assuming you are using for data source either DataSet or local database. Each time before you bind the dataGridView with new data source, create unbound columns with the same names as the names of your data source. Once they are created, you should hide them, because they will be needed when you refresh dataGridView's data source. The following sample code is aware of the data source columns names and therefore they are hard coded, but you can loop each time through the data source and create new collection of unbound columns, if it is necessary.
private void Form1_Load(object sender, EventArgs e)
{
this.dataGridView1.DataSource = GetDataSet();
this.dataGridView1.DataMember = "Students";
this.dataGridView1.Columns.Add("unboundColumn1", "ID");
this.dataGridView1.Columns.Add("unboundColumn2", "Name");
this.dataGridView1.Columns["unboundColumn1"].Visible = false;
this.dataGridView1.Columns["unboundColumn2"].Visible = false;
}
private void button1_Click(object sender, EventArgs e)
{
this.dataGridView1.Columns["unboundColumn1"].Visible = true;
this.dataGridView1.Columns["unboundColumn2"].Visible = true;
this.dataGridView1.DataSource = null;
}
private DataSet GetDataSet()
{
DataSet dataSet = new DataSet();
dataSet.Tables.Add("Students");
dataSet.Tables["Students"].Columns.Add("ID", typeof(int));
dataSet.Tables["Students"].Columns.Add("Name", typeof(string));
dataSet.Tables["Students"].Rows.Add(1, "John Joy");
dataSet.Tables["Students"].Rows.Add(2, "Ivan Nova");
dataSet.Tables["Students"].Rows.Add(3, "Michael German");
return dataSet;
}

Struggled with this for 24 hrs. Not sure why it works, but the solution that did not produce a runtime error for me is to dispose of the table adapter associated with the datagridview:
if (this.dataTableTableAdapter != null)
{
this.dataTableTableAdapter.Dispose();
}

Related

BindingSource is null even when the DataSource has regular data

I have a DataGridView that loads data from a file. I also want to use the DropDownFilter Column - I've used the one from Karl Erickson on Microsoft. It works all good while the columns are set in the Designer Mode.
I need to set the DGV and DropDownFilter columns programmatically since I don't always want to have all the columns with Filter. The problem is that the DGV is autogenerating its column type automatically.
The solution might be the DGV.AutoGenerateColumns = false, however this will throw a BindingSource error while adding new DropDownFilter column to the DGV, let me describe:
The DropDownFilter column has a property FilteringEnabled, where the following code returns null to the BindingSource data object, even when the DGV.DataSource contains relevant data:
BindingSource data = this.DataGridView.DataSource as BindingSource;
You can see in the image, that the DataSource is not empty, it has its columns and data as needed:
DataSource visualization
Is it possible to create the DTG with custom column type in the way I intend, or am I missing something? How can DataSource return null to BindingSource when this DataSource contains regular data?
Update 1
Minimal code to reproduce the err:
Form1.cs
// Create WinForm app, add DataGridView control and the code below
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
LoadToDtg();
}
private void LoadToDtg()
{
dataGridView1.AutoGenerateColumns = false;
// Prepare DataTable columns fill with data
DataTable dt = new DataTable();
dt.Columns.Add("Col1");
dt.Columns.Add("Col2");
dt.Columns.Add("Col3");
dt.Columns.Add("Col4");
dt.Rows.Add("ValueA1", "ValueA2", "ValueA3", "ValuA4");
dt.Rows.Add("ValueB1", "ValueB2", "ValueB3", "ValueB4");
dt.Rows.Add("ValueC1", "ValueC2", "ValueC3", "ValueC4");
// The DataSource binding could be used here too, however it yelds the same error
//dataGridView1.DataSource = dt;
foreach (DataColumn col in dt.Columns)
{
DataGridViewAutoFilterTextBoxColumn newColumn = new DataGridViewAutoFilterTextBoxColumn
{
HeaderText = col.ColumnName,
DataPropertyName = col.ColumnName
};
dataGridView1.Columns.Add(newColumn);
}
dataGridView1.DataSource = dt;
}
}
The DataGridViewAutoFilterTextBoxColum refers to already mentioned project # Microsoft page. I didn't paste it here since it has 1400+ lines of code. You can download the zip directly here

How to search or filter a column in C# datagrid view, datagridview source is a list

I use dapper to get a joined data from database, then store as a list, and use datagridview to display list,
Now I want to search a column by a textbox,
private void SetupDataTableAvailableTool() {
toolList = adapter.GetJoinedToolsData();
dgvAvailableTools.DataSource = null;
dgvAvailableTools.DataSource = toolList;
}
above code is display list in dgvAvailableTools.
List<Tools> toolFilterList = new List<Tools>();
BindingSource bs = new BindingSource();
bs.Filter = searchTextBox.Text;
dgvAvailableTools.DataSource = bs;
above solution is not working .
I tried below
(dgvAvailableTools.DataSource as DataTable).DefaultView.RowFilter =string.Format("Name='{0}'", searchTextBox.Text);
it give me an error Object reference not set to an instance of an object,
I tried to create datatable , but it is not working, code at below
DataTable dt = new DataTable("Products");
da.Fill(dt);
dataGridView.DataSource = dt;
can anyone tell me the solution? I dont need binding data to datagridview.
Thanks in advnace
When using a BindingSource filter you need to include the property name e.g. in this case Item is the property to filter on.
private void FilterButton_Click(object sender, EventArgs e)
{
if (string.IsNullOrWhiteSpace(searchTextBox.Text))
{
_customerBindingSource.RemoveFilter();
}
else
{
_customerBindingSource.Filter = $"Item = '{searchTextBox.Text}'";
}
}
how can I transfer this list to BindingSource bs
The code above sets a DataTable to the BindingSource were in this case _operations.CustomerDataTable is returns a DataTable.
See this code for assignment
Code which reads the data
Werther using a DataTable or a DataAdapter its semantics.
See also BindingSource Filter with Starts, contains, ends with and case sensitive options

Updating DataGridView after changing data source during run-time

public void sortAssets(string assetType)
{
DataTable newDataTable = new DataTable();
foreach(DataRow row in table.Rows)
{
if ((string)row["assetType"] == assetType)
{
string test = (string)row["assetType"];
newDataTable.ImportRow(row);
}
}
dataGridViewAssets.DataSource = null;
dataGridViewAssets.DataSource = newDataTable;
dataGridViewAssets.Refresh();
}
Above is a piece of code extracted from a program I'm working on.
I want to change the data-source to newDataTable at runtime. To do that, I have first cleared the the datagridview using dataGridViewAssets.DataSource = null;. Then, I changed the data source (dataGridViewAssets.DataSource = newDataTable;). At last, I refreshed the datagridview by dataGridViewAssets.Refresh();.
However, the visual datagridview does not get updated. Instead, all data in it get erased and remains blank.
What is wrong here and what must be changed?
Unless you specifically need to clone rows, this would be a lot simpler:
public void FilterAssets(string assetType) {
(dataGridViewAssets.DataSource as DataTable).DefaultView.RowFilter = "$[assetType] = '{assetType}'";
}
If you've made your DGV based on a bindingsource, it's
public void FilterAssets(string assetType) {
(dataGridViewAssets.DataSource as BindingSource).Filter = "$[assetType] = '{assetType}'";
}

Binding to DataTable that is a Property of another Object: System.ArgumentException Column does not belong to the table

I am creating a winform application and using data binding to display information about a collection of objects. I've successfully retrieved Strings and Lists from the object and displayed them on my form. I'm running into trouble displaying the object's DataTable.
The object has a DataTable property:
public DataTable Table { get; set; }
The table will be populated by reading a file, but for debugging right now I'm manually creating and populating the table like so:
private void CreateDataTable()
{
Table = new DataTable();
Table.Columns.Add("ID", typeof(int));
Table.Columns.Add("FuelKg", typeof(int));
Table.Columns.Add("Model", typeof(string));
Table.Rows.Add(1, 800, "Boeing 747");
Table.Rows.Add(2, 1023, "Airbus A380");
Table.Rows.Add(3, 62, "Cessna 162");
}
I use data binding to bind the DataTable to my DataGridView:
BindingSource bsAirplanes = new BindingSource();
BindingSource bsTable = new BindingSource();
//...additional code...
//databinding for datatable
bsTable.DataSource = bsAirplanes;
bsTable.DataMember = "Table";
dataGridView2.DataSource = bsTable;
dataGridView2.AutoGenerateColumns = true;
When I load the form on the first record everything looks great.
However, when I move to any other record, the DataGridView that's bound to my DataTable does not populate. For each column in my datatable, I get an error stating:
System.ArgumentException: Column 'ID' does not belong to the table .
at System.Data.DataRow.CheckColumn(DataColumn column)
at System.Data.DataRow.get_Item(DataColumn column, DataRowVersion version)
at System.Data.DataRowView.GetColumnValue(DataColumn column)
at System.Data.DataColumnPropertyDescriptor.GetValue(Object component)
at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetValue(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)
The DataGridView is now empty except for the column names.
I know that the columns do indeed belong to my table because I've manually stepped through the code and can see them in my DataTable object. It seems like there is some issue refreshing the data when I move to the next record. Perhaps the DataGridView is only bound to the DataTable in my FIRST Airplane object?
After many rounds of trial and error, I devised this solution. I am not sure it's the best solution, but it works. If there is a better way I'd love to know!
My suspicion that the bsTable BindingSource was linked only to the first object's DataTable seems to be correct. I need to manually update the bsTable's DataSource when I change the main object.
I added an event listener to my main DataGridView (bound to bsAirplanes). When the user selects a different row in the grid, the secondary DataGridView (bound to bsTable) is re-bound to the current Airplane's DataTable and the correct data populates.
In the Form1.Designer file:
this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_Changed);
In the Form.cs file:
private void dataGridView1_Changed(object sender, EventArgs e)
{
bsTable.DataSource = bsAirplanes.Current; //notice I am using bsAirplanes.Current, not bsAirplanes
bsTable.DataMember = "Table";
dataGridView2.DataSource = bsTable;
dataGridView2.AutoGenerateColumns = true;
}
I solved an error similar to this error by clearing and reseting the BindingSource before re-assigning its DataSource property like the following:
bsTable.DataSource = null;
bsTable.ResetBindings(true);
// ...
// recreate or reload myDataTable
// if I did not clear and reset the BindingSource,
// the following line throws the DataGridView.DataError
bsTable.DataSource = myDataTable.DefaultView;

add the new row client has entered to data source on radgirdview

I am new to using the telerik tools for winforms and I was wondering if anyone could help me to find the best way so that the client can add a new row on the radgrid and for it to show this change on the data source.
so far I have the radgrid set up so that the client can add a new row. I just need to bind it to the data source.
private void radGridView1_Click(object sender, EventArgs e)
{
this.radGridView1.AllowEditRow = false;
this.radGridView1.AllowAddNewRow = true;
this.radGridView1.AllowDeleteRow = false;
this.radGridView1.AddNewRowPosition = Telerik.WinControls.UI.SystemRowPosition.Top;
this.radGridView1.MasterTemplate.AddNewBoundRowBeforeEdit = true;
radGridView1.EnableAlternatingRowColor = true;
}
Have a look at the UserAddedRow event for RadGridView. This is fired after the user added a new row to the grid. You could then add the new entries to a source list or data table.
List<Foo> _lSource = new List<Foo>();
DataTable _tSource = new DataTable();
private void radGridView1_UserAddedRow(object sender, GridViewRowEventArgs e)
{
Foo foo = new Foo();
foo.Col1 = e.Row.Cells["col1"].Value.ToString();
foo.Col2 = e.Row.Cells["col2"].Value.ToString();
_lSource.Add(foo);
_tSource.Rows.Add(e.Row.Cells["col1"].Value.ToString(), e.Row.Cells["col2"].Value.ToString());
}
I added both possibilities in the same code snippet. Just choose one (list or table). I just created a random class to show you an example. You can create your own classes and name the properties as you want. Just note that the column (col1 and col2 in my example) must exist, otherwise you'll get a NullReferenceException. If you're using DataTable you have to add the columns once before adding rows.
_tSource.Columns.Add("col1");
_tSource.Columns.Add("col2");
I also recommend not to update the RadGridView properties on a click event of RadGridView. Because it is enough to set those properties once. Now you set them every time you click in your grid view. Either move them to the Load event of your form or set it directly in designer properties.
private void Form_Load(object sender, EventArgs e)
{
radGridView1.AllowEditRow = false;
radGridView1.AllowAddNewRow = true;
radGridView1.AllowDeleteRow = false;
radGridView1.AddNewRowPosition = Telerik.WinControls.UI.SystemRowPosition.Top;
radGridView1.MasterTemplate.AddNewBoundRowBeforeEdit = true;
radGridView1.EnableAlternatingRowColor = true;
}
RadGridView supports data binding to variety of data sources and CRUD operation will be handled for you automatically. Here you can find information on the supported data sources: Telerik UI for WinForms Documentation
And here is how to bind to a DataTable, where all CRUD operations work out of the box
RadGridView radGridView1 = new RadGridView();
this.Controls.Add(radGridView1);
radGridView1.Dock = DockStyle.Fill;
DataTable table = new DataTable();
table.Columns.Add("col1");
table.Columns.Add("col2");
table.Rows.Add("value1", "value1");
table.Rows.Add("value2", "value2");
radGridView1.DataSource = table;
Here is also a design time tutorial.

Categories