I have the following object:
CrossTabDataObject
{
string RowName{get;set;};
int RowId{get;set;}
List<string> CellContents = new List <string>();
//Constructor..... etc.
}
I'm building a dynamic crosstab grid using GridView in asp.net 3.5
I wish to bind to CellContents[0] for dynamic column 1, CellContents[1] for dynamic column 2 (dynamic column 0 is the RowName field from the CrossTabDataObject) etc. I am using:
object boundValueObj = null;
Control ctrl = (Control)sender;
IDataItemContainer dataItemContainer = (IDataItemContainer)ctrl.NamingContainer;
boundValueObj = DataBinder.Eval(dataItemContainer.DataItem, strSelectedID);
This code is in the InstantiateIn function of the gridview as I'm creating drop down list templates in each cell of the crosstab.
I have code (not shown) that sets strSelectedID depending on the column being created.
When strSelectedID is equal to "RowName" for dynamic column [0] the DataBinder.Eval function works fine and sets boundValueObj as expected. The problem comes when strSelectedID is set to "CellContents[n]" where n is the Column Index.
DataBinder.Eval only works with properties and fields of objects. How do I get around this?
Thanks,
Rich.
OK - stupid mistake by me!
Changing:
CrossTabDataObject
{
string RowName{get;set;};
int RowId{get;set;}
List<string> CellContents = new List <string>();
//Constructor..... etc.
}
to:
CrossTabDataObject
{
string RowName{get;set;};
int RowId{get;set;}
List<string> CellContents{get;set;}
//Constructor
public CrossTabDataObject()
{
CellContents = new List<string>();
}
}
made all the difference. In other words I made CellContents a property of the class.
Rich.
Related
I am programming UI with WPF for a month. So i am new in this world. This is my first ever post here and my motherlanguage isn't English. So if there is any mistake in my writing, sorry for that.
I have a problem with WPF and I am not able to find a solution for it. I am trying to make completely customizable DataGrid in WPF and I don't want the DataGrid to create columns or rows automatically.
I have an ObservableCollection named Sinif_Tutucu (means Class_Holder in my motherlanguage) which holds classes. These classes have the same Field and Properties, but their values are different. I am creating the columns one by one according to Fields and Properties in these classes. After this I am adding columns to DataGrid manually.
Then I am adding the rows with ItemsSource like this.
DataGrid_1.ItemsSource = Sinif_Tutucu;
This populates only properties in the DataGrid and columns made up of fields remain empty. I have searched this and i guess there is no way to bind Fields to DataGrid. Classes within Sinif_Tutucu have thousands of fields. So I can't turn fields to properties and I don't want to code the whole datagrid structure from scratch. Because WPF DataGrid structure offers many useful features which i am currently using. I am able to get Field names and their values or Property names and values. I just need to create each row myself (like columns) and populate their cells one by one with my hand with C#. Or somehow I need to convert these Fields to Properties programmatically. Is there any way to achieve this?
Supposing your class that you want to show in the datagrid looks like this
public class Data
{
public int Value;
public string Name;
public DateTime Date = DateTime.Now;
}
Because you cannot bind fields to DataGridColumns, you have to dynamically create the columns and the records. Here is a short snippet which you can use to do that. This method creates new dynamic objects in a List, which stores the same data as in your ObservableCollection. This List is set as the new ItemSource of your DataGrid. This snippet only creates DataGridTextColumns. You migth have to modify this solution, if want to use other DataGridColumns.
private void loadDataGrid()
{
List<dynamic> dataObjects = new List<dynamic>();
dynamic dataObject;
IDictionary<string, object> dataObjectValues;
var fields = typeof(Data).GetFields();
foreach (var item in Sinif_Tutucu)
{
dataObject = new System.Dynamic.ExpandoObject();
foreach (var field in fields)
{
dataObjectValues = (IDictionary<string, object>)dataObject;
dataObjectValues[field.Name] = field.GetValue(item);
}
dataObjects.Add(dataObject);
}
dataObjectValues = (IDictionary<string, object>)dataObjects[0];
foreach (var pair in dataObjectValues)
{
var binding = new Binding(pair.Key);
DataGridTextColumn col = new DataGridTextColumn() { Binding = binding, Header = pair.Key }; //You might want to use another DataGridColumn-Type
dataGrid.Columns.Add(col);
}
dataGrid.ItemsSource = dataObjects;
}
I was wondering if anyone had an example of pulling a csv list of options from the database and checking the rows based on the text value pulled. So say I have a grid view with options showing various programming languages. I would like to match those languages to the ones that have been saved in the Database.
O ASP.NET
O C#
O VB.NET
...
So, if my returned list of languages is just ASP.NET and VB.NET, how do I get the checkboxes of those grid view rows to be checked? I could use View State but I am thinking more a data-based set of information by stepping through the recordset and checking the items based on the returned dataset.
Surprised I was able to figure this one out but suddenly the answer was staring me in the face.
protected void SetLangs()
{
List<string> sellangs = new List<string>();
string langs = hfPrgLangs.Value;
string langtrim = langs.Replace(" ", "");
sellangs = langtrim.Split(',').ToList<string>();
foreach (DataListItem dl in dlLanguages.Items)
{
Label lblLangName = (dl.FindControl("lblLangName") as Label);
CheckBox isChk = (dl.FindControl("cbLang") as CheckBox);
for (int i = 0; i < sellangs.Count; i++)
{
if (sellangs[i].ToString() == lblLangName.Text.ToString())
{
isChk.Checked = true;
}
}
}
}
I have a gridview that I populate with values I get from a powershell command. For example my powershell command is get-command. I know the command returns the values. Here is my code however my gridview never shows the data.
ArrayList boxesarray = new ArrayList();
foreach (PSObject ps in commandResults)
boxesarray.Add(ps.Properties["Name"].Value.ToString());
boxes.DataSource = boxesarray;
boxes.DataBind();
I know the value is there because I replaced the last two lines with a label and was able to see the value.
boxlabel.text = boxesarray[4];
I must be missing something. Help please.
The GridView requires a collection or IEnumerable of classes which have properties, and the properties are mapped to columns.
An array like yours have value typed objects (strings) which has no roperties, so you can't bind the properties to the columns.
ArrayList boxesarray = new ArrayList();
You could create a simple class like this:
public class PropertyContainer
{
public string Value {get;set;}
}
// NOTE: you can override ToString(); to customize String.Format behaviour
// and to show it in the debugger (althought there's other way for this, using
// DebuggerDisplayAttribute)
And create and populate an array of this class, which will be correctly bound to the datagrid.
foreach (PSObject ps in commandResults)
boxesarray.Add(
new PropertyContainer { Value = ps.Properties["Name"].Value.ToString()});
boxes.DataSource = boxesarray;
boxes.DataBind();
Other option is to convert your array to an array of objects using LINQ. You can even use anonymous object if the data grid columns are set to be automatically created.
// anonymous type
var dataForBinding = boxesArray.select(val => new {Value = val});
// array of the class
var dataForBinding = boxesArray.select(val => new PropertyContainer
{ Value = val });
You can bind this data to your gridview, and it will work perfectly.
You can try
.DataSource = (from ps in commandResults
select { Name:ps.Properties["Name"].Value.ToString() }).ToList();
Or
.DataSource = (from name in yourarraylist
select { Name:name.ToString() }).ToList();
I'm using a DataGridView binding its datasource to a List, and specifying the properties for each column.
An example would be:
DataGridViewTextBoxColumn colConcept = new DataGridViewTextBoxColumn();
DataGridViewCell cell4 = new DataGridViewTextBoxCell();
colConcept.CellTemplate = cell4;
colConcept.Name = "concept";
colConcept.HeaderText = "Concept";
colConcept.DataPropertyName = "Concept";
colConcept.Width = 200;
this.dataGridViewBills.Columns.Add(colConcept);
{... assign other colums...}
And finally
this.dataGridViewBills.DataSource=billslist; //billslist is List<Bill>
Obviously Class Bill has a Property called Concept, as well as one Property for each column.
Well, now my problem, is that Bill should have and Array/List/whateverdynamicsizecontainer of strings called Years.
Let's assume that every Bill will have the same Years.Count, but this only known at runtime.Thus, I can't specify properties like Bill.FirstYear to obtain Bill.Years[0], Bill.SecondYear to obtain Bills.Years[1]... etc... and bind it to each column.
The idea, is that now I want to have a grid with dynamic number of colums (known at runtime), and each column filled with a string from the Bill.Years List. I can make a loop to add columns to the grid at runtime depending of Bill.Years.Count, but is possible to bind them to each of the strings that the Bill.Years List contains???
I'm not sure if I'm clear enough.
The result ideally would be something like this, for 2 bills on the list, and 3 years for each bill:
--------------------------------------GRID HEADER-------------------------------
NAME CONCEPT YEAR1 YEAR2 YEAR3
--------------------------------------GRID VALUES-------------------------------
Bill1 Bill1.Concept Bill1.Years[0] Bill1.Years[1] Bill1.Years[2]
Bill2 Bill2.Concept Bill2.Years[0] Bill2.Years[1] Bill2.Years[2]
I can always forget the datasource, and write each cell manually, as the MSFlexGrid used to like, but if possible, I would like to use the binding capabilities of the DataGridView.
Any ideas? Thanks a lot.
I recently ran into this same problem. I ended up using DataGridView's virtual mode instead of binding to a data source. It doesn't have exactly the same features as binding, but it's still a lot more powerful than populating each cell manually.
In virtual mode, the DataGridView will fire an event whenever it needs to display a cell, which essentially means you can populate the cell however you please:
private void my_init_function() {
datagridview.VirtualMode = true;
datagridview.CellValueNeeded += new System.Windows.Forms.DataGridViewCellValueEventHandler(datagridview_CellValueNeeded);
}
private void datagridview_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
e.Value = get_my_data(e.RowIndex, e.ColumnIndex);
}
You could use reflection to set up and fill the DataGridView. I've done this with a single type, but I don't see why it couldn't be extended to your data structure.
To set up the DataGridView:
// Create the columns based on the data in the album info - get by reflection
var ai = new AlbumInfo();
Type t = ai.GetType();
dataTable.TableName = t.Name;
foreach (PropertyInfo p in t.GetProperties())
{
// IF TYPE IS AN ARRAY (OR LIST) THEN ADD A COLUMN FOR EACH ELEMENT
var columnSpec = new DataColumn();
// If nullable get the underlying type
Type propertyType = p.PropertyType;
if (IsNullableType(propertyType))
{
var nc = new NullableConverter(propertyType);
propertyType = nc.UnderlyingType;
}
columnSpec.DataType = propertyType;
columnSpec.ColumnName = p.Name;
dataTable.Columns.Add(columnSpec);
}
dataGridView.DataSource = dataTable;
Then to populate the DataGridView:
// Add album info to table - add by reflection
var ai = new AlbumInfo();
Type t = ai.GetType();
// WOULD NEED TO INCREASE BY LENGTH OF ARRAY
var row = new object[t.GetProperties().Length];
int index = 0;
foreach (PropertyInfo p in t.GetProperties())
{
// IF TYPE IS AN ARRAY (OR LIST) THEN ADD EACH ELEMENT
row[index++] = p.GetValue(info, null);
}
dataTable.Rows.Add(row);
This is just the code I used, so you'll have to modify the code to handle your year array/list.
i develop a webpage in that i need to add value field and text field to listbox item
i tried the following code , but it's not working , Please help me to solve the issue .
Thanks in advance
string[] category = new string[100];
char[] delimeter = { '~' };
category = Convert.ToString(dtable.Rows[0].ItemArray[5]).Split(delimeter);
for (int h = 0; h < category.Length; h++)
{
ListItem lstitem = lstCategory.Items.FindByText(category[h]);
if (lstitem != null)
{
lstSelCategory.DataTextField = category[h];
lstSelCategory.DataValueField = lstitem.Value;
}
}
lstSelCategory.DataBind();
}
DataValueField and DataTextField are for assigning which properties are displayed and used as values for the assigned DataSource, NOT for adding items to the List.
EDIT:
It looks to me as though you're looping through some categories from a DataTable, finding a matching item in another ListBox and then trying to add that item to another ListBox... You should be using the Add method of the ListBox (if that's what the Control is).
lstSelCategory.Items.Add(new ListItem(category[h], lisitem.Value));
ListBox.DataTextField and ListBox.DataValueField are used in conjuction with ListBox.DataSource.
See this for further information.