Unexpected result in deleting DataGridView Columns - c#

DataTable dt = new DataTable();
dt.Columns.Add("col1");
dt.Columns.Add("col2");
dt.Columns.Add("col3");
dt.Columns.Add("col4");
dt.Columns.Add("col5");
dataGridView1.DataSource = dt;
dataGridView1.Columns.RemoveAt(3);
dataGridView1.Columns.RemoveAt(2);
dataGridView1.Columns.RemoveAt(0);
In this program, I created a DataTable with 5 columns. This will be the DataSource of the DataGridView. Some columns in the DataTable doesn't need to be seen by the user, but will be used by the program later on.
After the last line, the columns are arranged as : col2, col5, col1, col3, col4. Why does it appear like this? Shouldn't it be removed from the DataGridView? What should I do to make it appear as "col2, col5"?
EDIT: I want to remove some Columns from the DataGridView, yet still be available in the DataTable. Also, it works inside an event (like Button_Click)
EDIT: I still haven't figured out why this is happening. I have no choice but to create another thread (BackgroundWorker) to do this...
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
DataTable dt = new DataTable();
int i;
dataGridView1.Invoke((MethodInvoker)delegate
{
dt.Columns.Add("col1");
dt.Columns.Add("col2");
dt.Columns.Add("col3");
dt.Columns.Add("col4");
dt.Columns.Add("col5");
dataGridView1.DataSource = dt;
dataGridView1.Columns.RemoveAt(3);
dataGridView1.Columns.RemoveAt(2);
dataGridView1.Columns.RemoveAt(0);
});
}
As far as I can tell, Haris Hasan was right; that the Form containing the DataGridView should appear at least once. But I'm still confused why...

As far as I know you will have to display DataGridView once before you can remove any column. Try this by displaying DataGridView one time and then delete the columns and see what happens

Instead of removing the columns you could try setting their visibility...
dataGridView1.DataSource = dt;
dataGridView1.Columns[3].Visible = false;
dataGridView1.Columns[2].Visible = false;
dataGridView1.Columns[0].Visible = false;

You can use DisplayIndex property of the DataGridView to order the columns. In order to hide a column you can set false to the Visible property of a particular column.
dataGridView1.Columns["ColumnTobeHided"].Visible = false;

If you don't want columns in the grid for all of the columns in the table, set datagridview.AutoGenerateColumns to false before binding the datatable to the datasource. Then create and bind the datagridview columns you actually want to have.
AutoGenerateColumns defaults to true, and yet it very seldom gives us what we really want. Take the time to build your datagridview columns exactly as you want and don't trust the default processing.

Related

Replace int column in Data Table with combobox for DataGridView (Winforms)

I have a DataTable with some integer values (assume 0 => 'open', 1 => 'proceeding', 2 => 'free' etc.) and in a dgv I want to allow the user to change that value, but with a combobox and with string values. So I created to test this a simple winform app
public Form1()
{
InitializeComponent();
DataTable dt = new DataTable();
dt.Columns.Add("test");
dt.Rows.Add(1);
dt.Rows.Add(2);
DataTable source = new DataTable();
source.Columns.AddRange(new DataColumn[] { new DataColumn("Value", typeof(int)), new DataColumn("Display", typeof(string)) });
source.Rows.Add(0, "zero");
source.Rows.Add(1, "one");
source.Rows.Add(2, "two");
dataGridView1.DataSource = dt;
var testTextColumn = new DataGridViewComboBoxColumn();
testTextColumn.HeaderText = "Text";
testTextColumn.Name = "testText";
testTextColumn.DataSource = source;
testTextColumn.DisplayMember = "Display";
testTextColumn.ValueMember = "Value";
dataGridView1.Columns.Add(testTextColumn);
}
So far so good, I thought I could simply make the test column invisible and only have the testText column visible (in the final app), but how does one combine the to values, i.e. when I change something in the cb update the value of the datatable? I could do it by changeEvents, but that seems rather impractical. Is there some sort of databinding?
There are three (3) things wrong in your posted code to achieve what you describe.
1-The line of code…
dt.Columns.Add("test");
… is defaulting to a string value. Therefore, the combo box would throw a DataError when you try to bind the “Value” column from the source table. So, you need to specify the int type column in the data. Like…
dt.Columns.Add("test", typeof(int));
2- Before the code set the grids DataSource the code needs to specify that we do NOT want the grid to AutoGenerateColumns. Otherwise, we will end up with two columns. In addition, this grid property is NOT a displayed property in the “Designer.” You will need to set this property BEFORE you add the data source and you need to set this property in your code. Something like…
dataGridView1.AutoGenerateColumns = false;
3- When the code creates the combo box column, it never identifies “which” column in the grids DataSource we want to bind the combo box column to. That is the purpose of the columns DataPropertyName. So, you need to add this line of code in the combo box definition…
testTextColumn.DataPropertyName = "test";
Making these changes, should display only the combo box column.
creates a cell change event, then takes the number of the row you changed and you have access to the columns with the indexes ...
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.CurrentRow != null)
{
DataGridViewRow dgvRow = dataGridView1.CurrentRow;
// do what u want here like
int teste = Convert.ToInt32(dgvRow.Cells[1].Value);
}
}

Fill DataGridView on condition from database

I have MySQL database and a DataGridView in C# and to fill the DataGridView I do the following:
schoolDataSet schl = new schoolDataSet();
schoolDataSetTableAdapters.studentinfoTableAdapter adptr = new schoolDataSetTableAdapters.studentinfoTableAdapter();
adptr.Fill(schl.studentinfo);
dataGridView1.DataSource = schl.studentinfo.DefaultView;
and undesired columns I make them visible = false from DataGridView properties but I came with a problem if I want to specify what data (rows) to fill in DataGridView such applying a where condition like:
fill data in DataGridView WHERE IsActive = 1 so can I still use the above code with some modifications or I have to write SQL query and fill the DataGridView manually ?
After searching and trying tons of codes I got it as following in simplest code:
In the code above just comment out last line which is dataGridView1.DataSource = schl.studentinfo.DefaultView; or simply replace it with the following
DataView dv = new DataView(schoolDataSet.studentinfo, "IsActive = 'false'", "id", DataViewRowState.CurrentRows);
Which creates a new DataView and filters according to IsActive column with false value, the third parameter id is to sort based-on, and finally you can write another line
dataGridView1.DataSource = dv; that will tell the DataGridView to load data from DataView.
Hope to save someone's time.
Big thanks goes to #Karthik Ganesan

Datasource not reflecting sorting in DataGridView

I am binding a DataTable as the DataSource of a DataGridView. I enabled the SortMode property to Automatic for all DataGridViewColumn. But when I am sorting on DataGridView the Sort change is not being reflected in the underlying DataSource which is the DataTable.
For example:
DataTable table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Age", typeof(int));
table.Rows.Add("Alex", 27);
table.Rows.Add("Jack", 65);
table.Rows.Add("Bill", 22);
dataGridView1.DataSource = table;
Now if I was to get the selected row like below it will always return the row at 0 Index in the DataTable even after sorting which is Alex, 27.
DataRow newRow = table.NewRow();
newRow.ItemArray = table.Rows[dataGridView1.Rows.IndexOf(dataGridView1.SelectedRows[0])].ItemArray.Clone() as object[];
Can someone please suggest how I should go about this situation?
First of all the DataTable object is detached from DataGridView even if you bind it to DataSource, that is, if you change your DataGridView it will not affect your DataTable. And in your case you want the sorting in DataGridView to be reflected in DataTable. And so for that reason you need to catch an event every time there is changes in ordering/sorting in DataGridView. You need to catch therefore for that regard the ColumnHeaderMouseClick event of the DataGridView.
Another important thing is, in achieving a synchronize sorting of both DataTable and DataGridView is the DefaultView method of Datable class that has the Sort property. So, what we are going to do is every time the DataGridView is changed sorting-wise we will sort the DataTable also.
First of all we need to make a DataTable object global so that we could access it anywhere later on.
DataTable table;
Secondly, we need to initialize an event listener for ColumnHeaderMouseClick and for our practical purpose we will set it at Form constructor.
InitializeComponent();
dataGridView1.ColumnHeaderMouseClick += new DataGridViewCellMouseEventHandler(dataGridView1_ColumnHeaderMouseClick);
We then have this empty Mouse event handler:
void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
}
And if the above method doesn't automatically come out, just copy and paste in your code.
And for the sake of illustration we will add the DataTable during the Form Load and in this case I am going to use your own code:
table = new DataTable();
table.Columns.Add("Name");
table.Columns.Add("Age", typeof(int));
table.Rows.Add("Alex", 27);
table.Rows.Add("Jack", 65);
table.Rows.Add("Bill", 22);
dataGridView1.DataSource = table;
And then finally we will put some code in the ColumnHeaderMouseClick event:
void dataGridView1_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (dataGridView1.SortOrder.ToString() == "Descending") // Check if sorting is Descending
{
table.DefaultView.Sort = dataGridView1.SortedColumn.Name + " DESC"; // Get Sorted Column name and sort it in Descending order
}
else
{
table.DefaultView.Sort = dataGridView1.SortedColumn.Name + " ASC"; // Otherwise sort it in Ascending order
}
table = table.DefaultView.ToTable(); // The Sorted View converted to DataTable and then assigned to table object.
}
You could now use table object and sorted according to the sorting order of the DataGridView.
Just to confirm my claim, we will make a button in your form named button1 and when clicked it will show the first row and the sorted column value, like:
private void button1_Click(object sender, EventArgs e)
{
String sortedValue = dataGridView1.SortedColumn.Name == "Name" : table.Rows[0][0].ToString() ? table.Rows[0][1].ToString();
MessageBox.Show(sortedValue);
}
You can put your DataTable into BindingSource container and set this class to data source of DataGridView.
BindingSource bindingSource1 = new BindingSource();
bindingSource1.DataSource = dataTable;
dataGridView1.DataSource = bindingSource1;
// another grid view options...
To learn about BindingSort, see this link.
Old question, but still no easy solution mentioned, so I post it here for the people looking for the answer nowadays:
DataRow row = ((DataRowView)yourDataGridView.SelectedRows[0].DataBoundItem).Row;
int index = yourDataTable.Rows.IndexOf(row);
index will be the index of the row in your DataTable corresponding with the selected row in DataGridView, however you have sorted it.
For others coming here for same reason as I.
I couldn't get the underlying data sorted either, thus when I was deleting a row, it was deleting the wrong one.
I found DataTable will not be sorted but only DataTable.DefaultView will be.
So instead of DataRow row = dataTable.Rows[0];
You would do DataRow row = dataTable.DefaultView[0].Row;
I found another alternative solution where I get value of a unique column from my DataGridView and then query the underlying DataSource the DataTable to get the rows even though the DataTable is not sorted.
But I'd like to know how to sort the DataTable though.
Solution

Currency Culture Formatting not applying on DataGridView Column

I have 2 DataGridViews (DGV), and in both I have currency columns which I want to format. The code I'm writing seems to work in one, but not in the other.
Both the DGV's are set up this way: Data is first loaded into a DataTable. A BindingSource then links to this DataTable. And lastly the DGV's use this BindingSource object for their data.
I use the following code in the form's Load event to customize both DGVs' currency columns:
dataGridView.Columns[columnIndexHere].DefaultCellStyle.FormatProvider = CultureInfo.GetCultureInfo("de-DE");
dataGridView.Columns[columnIndexHere].DefaultCellStyle.Format = String.Format("c")
Seems to format the columns in one DGV both not the other. Also, the DGV in which its NOT working, doesn't even have that much functionality code in its parent Form .. I have checked the code, and the DGV's properties, to see if I'm changing the formatting somewhere else, but I haven't found anything ..
The ONLY slight difference between the way the two DGV's load data is that, for the first DGV's DataTable (in which formatting works), data is loaded thru a SELECT statement (via my own functions) ... In the second DGV's DataTable (for which formatting is NOT working), I don't load any data from DB, and instead just manually define the columns (in the DataTable), because in this scenario the user needs to input the data ..
Any clues why formatting not working on the second DGV ?
EDIT: Adding More Information:
To demonstrate the problem, I've created a new C# winforms project, added just one DataGridView on it, and added the following code to the Load event. Even for this code, the currency formatting is NOT being done:
DataTable dataTable = new DataTable();
dataTable.Columns.Add("ColA");
dataTable.Columns.Add("ColB");
dataTable.Columns.Add("ColC");
dataTable.Rows.Add("John", 832.293, "London");
dataTable.Rows.Add("Alice", 32972978.20489, "Atlanta");
dataTable.Rows.Add("Mark", 9184793284739, "Tokyo");
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = dataTable;
dataGridView1.DataSource = bindingSource;
var format = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone();
format.CurrencySymbol = "Mn. ";
dataGridView1.Columns["ColB"].DefaultCellStyle.FormatProvider = CultureInfo.GetCultureInfo("de-DE");
dataGridView1.Columns["ColB"].DefaultCellStyle.Format = String.Format("c");
Hope this helps in diagnosing the problem more ..
you don't need a BindingSource to list all rows, just
dataGridView1.DataSource = dataTable,
and since you're using a DataTable, remove this part
dataGridView1.Columns["ColB"].DefaultCellStyle.Format = String.Format("c");
and try to use the CellFormatting event.
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == 1) //Column ColB
{
if (e.Value != null)
{
e.CellStyle.Format = "c";
}
}
}
I hope it will help :)
(answer previously from the question)
Added the following line after defining the two columns, and now it works:
qBDFrmDTForDisplay.Columns["Combined Price"].DataType = Type.GetType("System.Decimal");

How can I clear rows in DataGridView with C#?

Following Error in this line.
datagridview1.Rows.Clear()
but this line gives error:
Cannot clear this list.
I also had similiar problem when I try to clear DataSource of a DataGridView after I had binded it to a DataTable with:
DataTable DT = ... ; // fill it
datagridview1.DataSource = DT;
when I try to clear it's rows later with the following code:
datagridview1.DataSource = null
I get this error:
ERROR: Object reference not set to an instance of an object
This object reference ERROR problem already solved in here. But I managed to solve my own problem (clearing DataGridView rows) with this code:
DataTable DT = (DataTable)datagridview1.DataSource;
if (DT != null)
DT.Clear();
I know that this question was asked a very long time ago, but I hope my solution would solve someone problems.
Is your DataGridView bound to a DataSource, i think thats why its not allowing you to clear it since its bound to an underlying DataTable or List.
you could try setting the DataSource Property to null
datagridview1.DataSource = null; for clearing
private void button_Limpar_Click(object sender, EventArgs e)
{
DataTable DT = (DataTable)dataGridView_Cidade.DataSource;
if (DT != null)
DT.Clear();
}
#endregion
Simply add this line at beginning of your event:
dgv_nameOfGridView.DataSource=false;
Now every time you click it will erase the dgv..
You have to Clear datasource not datagridview rows.
datagridview1.DataSource = null;
Another way is
1) Dont assign direct datasource to gridview.
add rows from datatable to gridview
foreach (DataRow row in dataTable.Rows)
{
var dataGridRow = new DataGridViewRow();
dataGridRow.CreateCells(datagridview1);
for (int i = 0; i < row.ItemArray.Length; i++)
{
dataGridRow.Cells[i].Value = row.ItemArray[i];
}
datagridview1.Rows.Add(dataGridRow);
}
then use
datagridview1.Rows.Clear()
You can use this simple method:
First clear your DataTable and then refresh your DataGridView
dataTable.Clear();
dataGridView.Refresh();
Hope this help
Easy solution is to clear the DataSet.
ds.Clear();
Since you are using a bound grid, have you tried to call your loading
function twice and verified that the data is not doubling?
Since it is bound, loading twice ought to not duplicate the data.
http://www.vbforums.com/showpost.php?s=aa5f116586c00a2d9ea15e3727fc5c2f&p=2841192&postcount=9
First clear DataSource and then clear DataGridView
in VB
datagridview1.DataSource = Nothing
datagridview1.Rows.Clear()
hope help
If you load your DataGridView with a parameter, you can send an empty parameter to it. This will clear your DataGridView without having to set its DataSet to null.
For example, I load my DataGridView with a Code, when I fill a TextBox.
this.dataTable1TableAdapter.Fill(this.ds_MyDataSet.DataTable1, TextBox1.Text);
If I want to clear its content, then
this.dataTable1TableAdapter.Fill(this.ds_MyDataSet.DataTable1, "");
Here we are 8 years later.
Although
datagridview1.DataSource = null;
is a satisfactory answer for most, for me this removes all customizations I've added to the columns in design view. So hidden columns appears if I want to clear out the rows.
So rather than clear out rows:
datagridview1.Rows.Clear()
Clear out the DataTable or DataView that you used to set up the DataGridView. Note you don't have to check if something is null nor worry about Object not set to reference errors.
So here's how I did mine:
//Populate the datagridview
DataTable _DT = new DataTable();
BindingSource _BS = new BindingSource();
//Initially fill up your datatable with stuff
//You can call this method again if data needed to be changed
public void fillDT(int id) {
_DT = fillUpDataTableWithStuffFromDB(id);
_BS.DataSource = _DT.DefaultView;
datagridview1.DataSource = _BS;
_BS.ResetBindings(false);
}
//You can use this method to mimic the functionality above
//But rather fetching data, just clear out the datatable and pass it in
public void clearDT() {
_DT.Clear();
datagridview1.DataSource = _DT.DefaultView;
datagridview1.Refresh();
}
As you can see above, I just cleared out the datatable, and passed that into the datagrid. This kept all my properties I set on the datagridview column.
foreach (DataGridViewRow item in this.datagridview.Rows)
{
datagridview.Rows.RemoveAt(item.Index);
}
I had the same problem I tried with many solutions.
In the end I realized that we can't clear the DataGridView if we use it's property "DGV.Datasource" because DGV takes its data from the dataset so you need to clear the DataTable rows
Dataset.Tables["TableName"].Rows.Clear();
If you use this function in the Load of the Form you need to add a condition
if (DataSet.Tables["TableName"] !=null)
Dataset.Tables["TableName"].Rows.Clear();
or you will get this error
Object reference not set to an instance of an object.

Categories

Resources