How to get cell value in GridView (WITHOUT using cell index) - c#

how to get cell value from gridview without using cell index?
Let say the first column name in my table is "RowNumber".
instead of using
string name = GridView1.Rows[0].Cells[0].Text;
Something like
string name = GridView1.Rows[0].Cells["RowNumber"].Text;

You could cast the GridViewRow's DataItem property into a DataRowView, and then reference the column names:
DataRowView rowView = (DataRowView)GridView1.Rows[0].DataItem;
string name = rowView["RowNumber"].ToString();
You can't do this from the Cells collection, because they are just TableCell objects, and they don't know anything about the underlying data.
The DataItem property represents the values in that row from the underlying datasource, so that's what you want to deal with.

You can use datakeys to access any data you want from the row index.
In the markup of the gridview, add all the fields you want to be able to access to the gridview.
<asp:GridView ID="gvTransactionHistory" runat="server"
AutoGenerateColumns="false"
onselectedindexchanging="gvTransactionHistory_SelectedIndexChanging"
DataKeyNames="ID, AnyField">
These datakeys can be accessed in the code behind with the row index
var id = gvTransactionHistory.DataKeys[rowIndex].Values["ID"];
var AnyField = gvTransactionHistory.DataKeys[rowIndex].Values["AnyField"];

here is a function I wrote. since we typically get the same list of fields over and over again, I cached the index lookups.
private static readonly HybridDictionary cache = new HybridDictionary();
public static object[] GetColumnValues(
this GridView g,
int rownumber,
string columnNamesCommaSeparated)
{
var dataView = g.DataSource as DataView;
if (dataView != null)
{
DataRow dataRow = dataView[rownumber].Row;
object[] items = dataRow.ItemArray;
DataColumnCollection columns = dataRow.Table.Columns;
string lookupkey = g.ID + columnNamesCommaSeparated;
var colids = cache[lookupkey] as int[];
int columnCount;
if (colids == null)
{
string[] columnNames = columnNamesCommaSeparated.Split(',');
columnCount = columnNames.Count();
colids = new int[columnCount];
for (int i = 0; i < columnCount; i++)
{
colids[i] = columns.IndexOf(columnNames[i]);
}
cache.Add(lookupkey, colids);
}
columnCount = colids.Length;
var values = new object[columnCount];
for (int i = 0; i < columnCount; i++)
{
values[i] = items[colids[i]] ?? "";
}
return values;
}
return null;
}
to use it do something like
object[] values = g.GetColumnValues(e.Row.DataItemIndex, "Firstname,Lastname,CompanyName");
if (values != null)
{
string header = Server.HtmlEncode(values[0] + " " + values[1] + " # " + values[2]);
}
// do whatever you want with this value

Related

How can I save rearranged column positions when reading out a DataGrid?

I have a DataGrid implemented in a WPF-window inside a VSTO-AddIn, which is supposed to preview data to the user before it is pasted to an existing Excel-sheet. The CanUserSortColumns-Property is set to true, so the user is able to rearrange the columns before they are read out and pasted to the sheet. However, when I read out the DataRows from the DataGrid, as shown below, the columns are back in their original position.
object[,] dataArray = new object[allRows, allCols];
for (int r = 0; r < allRows; r++)
{
DataRow row = ClientGrid.Rows[r];
for (int c = 0; c < allCols; c++)
{
dataArray[r, c] = row[c];
}
}
Here is my question: Is there any way to fix this the quick way or at least to track the changes of column display indices in order to rearrange the column order in the code with every change of the columns display order?
I've already tried working something out with the DisplayIndex-property but I did not quite get the hang of the numbers it spits out.
You could order the columns by the DisplayIndex property and use reflection to export the values using reflection, e.g.:
public static void ExportUsingRefection(this DataGrid grid)
{
if (grid.ItemsSource == null || grid.Items.Count.Equals(0))
throw new InvalidOperationException("You cannot export any data from an empty DataGrid.");
IEnumerable<DataGridColumn> columns = grid.Columns.OrderBy(c => c.DisplayIndex);
ICollectionView collectionView = CollectionViewSource.GetDefaultView(grid.ItemsSource);
foreach (object o in collectionView)
{
if (o.Equals(CollectionView.NewItemPlaceholder))
continue;
foreach (DataGridColumn column in columns)
{
if (column is DataGridBoundColumn)
{
string propertyValue = string.Empty;
/* Get the property name from the column's binding */
BindingBase bb = (column as DataGridBoundColumn).Binding;
if (bb != null)
{
Binding binding = bb as Binding;
if (binding != null)
{
string boundProperty = binding.Path.Path;
/* Get the property value using reflection */
PropertyInfo pi = o.GetType().GetProperty(boundProperty);
if (pi != null)
{
object value = pi.GetValue(o);
if (value != null)
propertyValue = value.ToString();
}
}
}
//...
}
}
}
}
Please refer to the following blog post for more information.
How to export data from a DataGrid in WPF: https://blog.magnusmontin.net/2013/09/29/export-data-from-a-datagrid/
I ended up doing the following:
Reading out the DisplayIndex-Property and the initial position of each column and ordering the tuples by the DisplayIndex-Property afterwards
var columnIndices = new List<Tuple<int,int>>();
var colCounter = 0;
foreach (var col in myDataGrid.Columns)
{
columnIndices.Add(Tuple.Create(col.DisplayIndex, colCounter));
colCounter += 1;
}
var sortedColumns = columnIndices.OrderBy(x => x.Item1).ToList();
Creating an empty DataTable and adding the original DataGrid's columns to it. Then I set the new DataTable's DataRow's cells equal to the cells of the DataRows of the original DataGrid.
var myDataTable = new DataTable();
foreach (var index1 in sortedColumns)
{
var columnName = myDataGrid.Columns[index1.Item2].ColumnName;
myDataTable.Columns.Add(columnName, myDataGrid.Columns[index1.Item2].DataType);
}
foreach (DataRow dr in myDataGrid.Rows)
{
var itemArray = new object[allCols];
var indexer = 0;
foreach (var index2 in sortedColumns)
{
itemArray[indexer] = dr[index2.Item2];
indexer += 1;
}
myDataTable.Rows.Add(itemArray);
}

c# get existing values in datagrid combobox items

On runtime I am changing some columns of datagridview into combobox columns. Now how do I get the existing distinct values in the combobox items? I am using entity model as datasource. My code is:
dgvLoadTable.DataSource = null;
var context = new AdminEntities();
var TableName = cboSelectTable.Text.ToString();
var rawData = context.GetType().GetProperty(TableName).GetValue(context, null);
var truncatedData = ((IQueryable<object>)rawData).Take(0);
var source = new BindingSource { DataSource = truncatedData };
dgvLoadTable.DataSource = source;
dgvLoadTable.ReadOnly = false;
dgvLoadTable.AllowUserToAddRows = true;
for (int row= 0; row < dgvLoadTable.Rows.Count; row++)
{
for (int col = 0; col < dgvLoadTable.Columns.Count; col++)
{
if (col == 2 || col == 4)
{
this.dgvLoadTable[col, row] = new DataGridViewComboBoxCell();
//var ss = dgvLoadTable.AsEnumerable().Select(_ => _.Field<string>(Columns[col])).Distinct();
}
}
}
dgvLoadTable.Refresh();
I'll assume that your code to create the list of values is working..
You need to load those values into the Items of a DataGridViewComboBoxCell; here is code that does that with a list of values:
if (col == 2 || col == 4)
{
var temp = this.dgvLoadTable[col, row].Value;
this.dgvLoadTable[col, row] = new DataGridViewComboBoxCell();
this.dgvLoadTable[col, row].Value = temp;
// if the value lists depend on the column, you may want to create them here!
((DataGridViewComboBoxCell)dgvLoadTable[col, row]).Items.AddRange(numbers.ToArray());
}
Note that for this we must cast the cell to a DataGridViewComboBoxCell as a normal cell doesn't have Items.
In my test case I have used a
List<string> values
and controlled the datatype of my column like this..:
dgvLoadTable[col, row].ValueType = typeof(string);
..beteween the two lines above, ie after creating and before filling the combobox.
Update: I have added two lines to save and restore the cells' values, as these get lost when changing the cells..

Add items and value of the drop down list from the database

I used this c# code to add items in dropdownlist(ddlSub) from the table sub_info. But what I want is to add the value of the items in dropdownlist(ddlSub) from the same table which also has a column named sub_id of datatype varchar(50).
private void bind_ddlSub()
{
ddlSub.Items.Insert(0, "-Choose-");
datatable_object = methodClassFunc.getData("select sub_name from sub_info");
for (int i = 0; i <= datatable_object.Rows.Count - 1; i++)
{
ddlSub.Items.Add(Convert.ToString(datatable_object.Rows[i]["sub_name"]));
}
}
You can use the ListItem object to add text and value for a dropdownlist item.
string subname = datatable_object.Rows[i]["sub_name"];
string subid = datatable_object.Rows[i]["sub_id"];
ddlSub.Items.Add(new ListItem(subname,subid));
Or you can bind your datasource like this:
ddlSub.DataSource = datatable_object;
ddlSub.DataTextField = "sub_name";
ddlSub.DataValueField = "sub_id";
ddlSub.DataBind();
You can do:
for (int i = 0; i <= datatable_object.Rows.Count - 1; i++)
{
ddlSub.Items.Add(new ListItem(Convert.ToString(datatable_object.Rows[i]["sub_name"]),
Convert.ToString(datatable_object.Rows[i]["sub_id"]));
}
Or you can bind the DataTable to your DropDownList and the specify DataTextField for display and DataValueField to get the value on index changed event like:
ddlSub.DataSource = datatable_object;
ddlSub.DataTextField = "sub_name";
ddlSub.DataValueField = "sub_id";
ddlSub.DataBind();

ListBox Not displaying values when sorted alphabetically?

This is my sorting logic alphabetic wise
string selectedVal = lstSelectionTags.SelectedValue;
SortedList sortedItems = new SortedList();
for (int i = 0; i < lstSelectionTags.Items.Count; i++)
{
sortedItems.Add(lstSelectionTags.Items[i].Text, lstSelectionTags.Items[i].Value);
}
lstSelectionTags.Items.Clear();
lstSelectionTags.DataSource = sortedItems;
lstSelectionTags.DataTextField = "key";
lstSelectionTags.DataValueField = "value";
lstSelectionTags.DataBind();
when i display items first time in my Listbox by using the below give code
string valueField = Convert.ToString(lstSelectionSub.SelectedItem);
int catID = Convert.ToInt32(lstSelectionSub.SelectedValue);
util = new Utilities();
dt1 = util.GetSubTags_PD(catID, false);
string[] lines = new string[100];
List<string> lines1 = new List<string>();
for (int i = 0; i < dt1.Rows.Count; i++)
{
string s1 = dt1.Rows[i][0].ToString();
if (s1 != "")
{
lines = Regex.Split(s1, ",");
if (!lines1.Contains(lines.ToString()))
{
lines1.AddRange(lines);
}
}
}
lstSelectionTags.DataSource = lines1.Distinct();
lstSelectionTags.DataBind();
It works fine initially and displays the Data but when i do sorting and then try and access the values i don't get any value in the ListBox
EDIT: There seems to be some issue with sorting after sorting the Listbox has a key and value as the DataValue and DataText Field whereas when i rebind it there is no DataValue and DataText Field. Please help.
ISSUE SOLVED : Just used
if (lines1.Count > 0)
{
lstSelectionTags.DataSource = null;
lstSelectionTags.Items.Clear();
lstSelectionTags.DataSource = lines1.Distinct();
lstSelectionTags.DataTextField = null;
lstSelectionTags.DataValueField = null;
lstSelectionTags.DataBind();
}

How can I use the data in the selected rows in GridView and show that list on another page?

I am writing a web site in Visual Studio, something like an on-line library. I have a GridView on the first page that presents all of the books available from the data source and some other properties also contained in the data source. The GridView contains check boxes and the user can choose which books he wants to order by checking a box. My question is how can I use the data in the selected rows, the list of books with their properties and show that list on another page, so that the user is able to know which items he has selected?
I tried with a for loop on the FirstPage:
for (int i = 0; i < GridView1.Rows.Count; i++)
{
int bookID = (int)GridView1.DataKeys[i][0];
CheckBox cb = (CheckBox)GridView1.Rows[i].FindControl("CheckBox");
if (cb.Checked)
{
purchaseProductList.Add(bookID);
Response.Redirect("SecondPage.aspx?bookID" + i + "=" + bookID);
}
}
and then on the SecondPage:
for (int i = 0; i < 10; i++)
{
if (Request.QueryString["bookID" + i] != null)
{
DataRow row;
row = dtBooks.NewRow();
row["ID"] = Request.QueryString["bookID" + i];
dtBooks.Rows.Add(row);
}
}
GridView1.DataSource = dtBooks;
GridView1.DataBind();
but it didn't work. Any help? Thank you in advance.
you can use session to keep selected ids
List<string> ids = new List<string>();
for (int i = 0; i < GridView1.Rows.Count; i++)
{
int bookID = (int)GridView1.DataKeys[i][0];
CheckBox cb = (CheckBox)GridView1.Rows[i].FindControl("CheckBox");
if (cb.Checked)
{
purchaseProductList.Add(bookID);
ids.Add(bookID);
}
}
Session["Ids"] = ids;
Response.Redirect("SecondPage.aspx");
from second page you can access session and load those ids to grid
var list = (List<string>)Session["Ids"];
foreach (string id in list)
{
DataRow row;
row = dtBooks.NewRow();
row["ID"] = Request.QueryString["bookID" + id];
dtBooks.Rows.Add(row);
}
GridView1.DataSource = dtBooks;
GridView1.DataBind();

Categories