I have a form with a DataGridView widget and I need to get the index of the column with the selected name.
For example, let's say that I have a table with 2 columns: Name, Surname. I need a way to get index of the column name. The problem is that it changes all the time depending on the DataSource but that column always has the same name "Name".
Does anyone know how to solve the problem?
To retrieve a DataGridView column by name you simply reference it through the columns collection indexer:
datagridview1.Columns["columnName"]
Then you can get the column index from that column:
datagridview1.Columns["columnName"].Index;
Do note that if you use an invalid column name then this reference will return null, so you may want to check that the column reference is not null before using it, or use the columns collection .Contains() method first.
If I am right, e.ColumnIndex will also work for this. you can check the MSDN Documentation here
You can get the index by using the Index property of the DataGridViewColumn widget, as such:
ColumnName.Index
This avoids the need for checking whether the column name is valid at runtime as it will generate a compilation error if the column does not exist. This also makes refactoring easier.
I recommend you give the columns a sensible name (for example DCOL_SomeName) so that you can easily distinguish them. Including the name of the DataGridView widget would help if you have multiple DataGridView widgets on the same form.
create a static class below the code
public static class MyTools
{
public static int IndexByName(this DataGridView dgv, string name)
{
foreach(DataGridViewColumn col in dgv.Columns)
{
if(col.HeaderText.ToUpper().Trim() == name.ToUpper().Trim())
{
return col.Index;
}
}
return -1;
}
}
and then call it with your dataGridView
int index = datagridview1.IndexByName("columnName");
I have found it safer to use the column object's Name property, instead of using the column name as a string, because this allows for more consistent code refactoring in the future.
datagridview1.Columns[column1.Name].Index;
Also, it is important to first make sure the column is not null and, as others have said, that it is contained within the datagridview.
Related
I've some issues giving the columns a unique identifier using Teleriks RadSpreadsheet (Workbook, Worksheet etc).
Here is my problem: My first row is a header row, e.g.:
| Name (father) | Age | Name (mother) | ....
Those column headers in my first row aren't unique. They have been named exactly the same, although they are used for different things. To improve extendibility, I dont want to use indexes to find the specified column I am looking for. When I add another column inbetween, the program should still work fine without any adjustments.
Instead, my program should use a normal key to find the column. For example: My program gets an request to return the column, in which
What I've tried:
- Hidden columns are not available in the version I currently use.
- Finding the columns by an easy string search isnt working either, cause they arent unique, so if I search for the father name column, I have two columns with the header "name" and cannot differentiate, what exactly is the right column.
for (int i = 0; i < columnCount; i++)
{
//Check value equals searchtxt..
}
- I wasnt been able (havent found anything) to give the cells / columns a hidden name, like 'mother name' and 'father name')
Do you have any other idea?
You could use a data structure like Dictionary for example where you can define a key - which will be the "hidden name", and a value - the CellIndex of the header cell.
To keep the dictionary up-to-date you will have to subscribe to some events like
Worksheet.Cells.CellRangeInsertedOrRemoved
and update the cached names to match their eventually new CellIndex. This way you will use the dictionary to find the cell index corresponding to the name defined by you.
During a gridview => database update function, I use a column-by-column conversion to string in order to pass data back to my database as a whole command string. I'm aware that this sounds convoluted, so here is an example:
Classes in use:
InvoiceHandler.cs
Default.aspx.cs
Since this is a rather large snippet, here is a pastebin:
Default.aspx.cs: http://pastebin.com/Y3fJZ36Z
InvoiceHandler.cs: http://pastebin.com/ZsdAnDxr
At the first point of conversion (invoiceTableEdited.Columns["Column1"].ColumnName = "#K_INV";) I get a NullReferenceException error, assumedly because the method call in Default.aspx.cs
handler.invoiceTableEdited = ViewState["invoiceTable"] as DataTable;
handler.invoiceTableEdited.Rows[row.RowIndex]["K_INVOICE"] = sK_INVOICE;
appears to be having trouble.
What must I do to resolve this?
I'll be honest, it's not very clear how you're trying to create the column collection for the table 'InvoiceTableEdited'. What it looks like you're doing in OnUpdate is you are assigning a string variable to a row in the table with a given index and a column that doesn't currently exist. Your basically saying put this string into a cell with a row number of 'x' and a column name of "column1". At this point "column1" doesn't exist.
I'd create the columns you need first in InvoiceHandler.cs like this (assumes they're string):
invoiceTableEdited.Columns.Add("MyColumn1", typeof(string));
invoiceTableEdited.Columns.Add("MyColumn2", typeof(string));
Obviously if you have loads of columns and you don't care about their names then just create a loop and add them that way. This will give them the naming convention "ColumnN", where 'N' is the number. You can then assign a name to them by referencing there name ("Column1" for example) or using their index.
Seems like a really simple thing, but all of the research and everything I have tried just doesn't seem to work. I am using VS2013 and .Net 4.5
I have a 2 column WPF DataGrid that isn't using databinding. The grid is already populated with data from a SQLCE table and I want to select a row and return as a string the data in the cell of column 0 of the selected row.
I can see that the data is there in the debug watch window
I just don't know how to access that value so that I can use it.
private void dgPickList_MouseDoubleClick( object sender, MouseButtonEventArgs e )
{
selectItem();
this.Close();
}
private void selectItem()
{
_pickedItem = dgPickList.SelectedItem.ToString();
}
This code obviously doesn't work so well but it does let me see the cell data in a Non-Public members _values field.
I really appreciate any help.
Jeff
Cast the SelectedItem back to the original type you populated the grid with.
For example, if you use a DataTable, cast to a DataRow and grab the first column (here I'm assuming it's an integer type that represents a unique ID):
var id = ((DataRow)dgPickList.SelectedItem).Field<int>(0);
If you're using a collection of a custom class, something like this should work:
var id = ((MyClass)dgPickList.SelectedItem).Id;
use DataGrid.SelectedCells instead. This will return a collection of selected cells in which you can find the column you need to read.
eg:
var celldata=dataGrid1.SelectedCells[0];
var val=celldata.Column.GetCellContent(celldata.Item);
i have found several examples/questions about getting row numbers of the selected cells but not many about getting Column names.
i want to check if a column is named: Frequency. i check if the user select 2 rows bofore doing my stuff.
i tried the following approaches:
if (Dat.SelectedColumns[0].ToString() == "Frequency"
|| Dat.SelectedColumns[1].ToString() == "Frequency")
this was not working, my initially thought was that i needed the headernames to check, my next try:
if (Dat.SelectedColumns[0].HeaderText == "Frequency"
|| Dat.SelectedColumns[1].HeaderText == "Frequency")
this is not working, as selectedColumns remains null. (inex out of range exception)
is there a way to get the names of the selected columns/check if the name is "frequency"?
edit:
// get the Column name of the selected data
int Xcor = Dat.CurrentCellAddress.X;
string ColumnName = Dat.Columns[Xcor].Name;
this method is not working im my case, i need to get 2 ColumnNames, not only the current selected
I am not sure of the SelectionMode which you have set for the grid, since you need to look out for specific columns it would be better to go for CellSelect.
In that case you have dataGridView1.SelectedCells and by going through each you would have the RowIndex as well as the ColumnIndex which would help you identify the specific column.
If this is not what you intend please update the question.
In my DataGridView I'am displaying a buch of columns from one table. In this table I have a column which points to item in another table. As you may already guessed, I want to display in the grid in one column some text value from the second table instead of and ItemID.
I could not find a right example on the net how to do this.
Lets assume that I have two tables in databes:
Table Users:
UserID UserName UserWorkplaceID
1 Martin 1
2 John 1
3 Susannah 2
4 Jack 3
Table Workplaces:
WorkplaceID WorkplaceName
1 "Factory"
2 "Grocery"
3 "Airport"
I have one untyped dataset dsUsers, one binding source bsUsers, and two DataAdapters for filling dataset (daUsers, daWorkplaces).
Code which I am performing:
daUsers.Fill(dsUsers);
daWorkplaces.Fill(dsUsers);
bsUsers.DataSource = dsUsers.Tables[0];
dgvUsers.DataSource = bsUsers;
At this point I see in my dgvUsers three columns, UserID, UserName and UserWorkplaceID. However, instead of UserWorkplaceID and values 1,2,3 I would like to see "Factory", "Grocery" and so on...
So I've added another column to dgvUsers called "WorkplaceName" and in my code I am trying to bind it to the newly created relation:
dsUsers.Relations.Add("UsersWorkplaces", dsUsers.Tables[1].Columns["WorkplaceID"], dsUsers.Tables[0].Columns["UserWorkplaceID"]);
WorkplaceName.DataPropertyName = "UsersWorkplaces.WorkplaceName";
Unfortunately that doesn't work. Relation is created without errors but fields in this column are empty after running the program.
What I am doing wrong?
I would like to also ask about an example with LookUp combobox in DataGridView which allow me to change the UserWorkplaceID but instead of numeric value it will show a tex value which is under WorkplaceName.
Thanks for your time.
In my opinion, the best decision would be to use the DataGridViewComboBoxColumn column type. If you do it, you should create a data adapter with lookup data beforehand and then set DataSource, DataPropertyName, DisplayMember, and ValueMember properties of the DataGridViewComboBoxColumn. You could also set the DisplayStyle property to Nothing to make the column look like a common data column. That's it.
I don't know if you can do exactly what you want, which seems to be binding the DataGridView to two different DataTable instances simulataneously. I don't think the DataGridView class supports that -- or if it does it's a ninja-style move I haven't seen.
Per MSDN, your best bet is probably using the CellFormatting event on the DataGridView and check for when the cell being formatted is in the lookup column, then you could substitute your value from the other table. Use an unbound column for the WorkplaceName column, hide the UserWorkplaceID column and then implement the CellFormatting event handle to look up the value in the row, e.g.:
private void dgv_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (dgv.Columns[e.ColumnIndex].Name.Equals("WorkplaceName")
{
// Use helper method to get the string from lookup table
e.Value = GetWorkplaceNameLookupValue(
dataGridViewScanDetails.Rows[e.RowIndex].Cells["UserWorkplaceID"].Value);
}
}
If you've got a lot of rows visible, this might impact performance but is probably a decent way to get it working.
If this doesn't appeal to you, maybe use the DataTable.Merge() method to merge your lookup table into your main table. A quick glance at one of my ADO.NET books suggests this should work, although I have not tried it. But I'm not sure if this is too close to the idea suggested previously which you shot down.
As for your second question about the lookup combobox, you should really post it in a separate question so it gets proper attention.
You could make SQL do the job instead. Use a join to return a table with Workplace names instead of IDs, output that table into a dataset and use it instead.
eg.
SELECT A.UserID, A.UserName, B.WorkplaceID
FROM Users A
JOIN Workplaces B ON A.UserWorkplaceID = B.WorkplaceID
Then use its output to fill dsUsers.