Use DisplayNameAttribute in ASP.NET - asp.net

I want to bind a List to a GridView on a web page, but override the way the property names display via annotation. I thought System.ComponentModel would work, but this doesn't seem to work. Is this only meant for Windows Forms?:
using System.ComponentModel;
namespace MyWebApp
{
public class MyCustomClass
{
[DisplayName("My Column")]
public string MyFirstProperty
{
get { return "value"; }
}
public MyCustomClass() {}
}
Then on the page:
protected void Page_Load(object sender, EventArgs e)
{
IList<MyCustomClass> myCustomClasses = new List<MyCustomClass>
{
new MyCustomClass(),
new MyCustomClass()
};
TestGrid.DataSource = myCustomClasses;
TestGrid.DataBind();
}
This renders with "MyFirstProperty" as the column header rather than "My Column." Isn't this supposed to work?

When using .net 4 or later you can use gridview1.enabledynamicdata(typeof(mytype)). I haven't looked at all the types you can use there but I know the [displayname("somename")] works well but the [browsable(false)] doesn't omit the column from the grid. It looks like a knit one slip one from MS. at least you can easily rename column names and to omit a column I just declare a variable instead of using a property. It has the same effect...
Just by the way, using the designer to create columns is the easy way out but to just show a different column name takes way to much time especially with classes with many fields.

What SirDemon said...
The answer appears to be no, you can't. At least not out of the box.
The System.Web.UI.WebControls.GridView uses reflected property's name:
protected virtual AutoGeneratedField CreateAutoGeneratedColumn(AutoGeneratedFieldProperties fieldProperties)
{
AutoGeneratedField field = new AutoGeneratedField(fieldProperties.DataField);
string name = fieldProperties.Name; //the name comes from a PropertyDescriptor
((IStateManager) field).TrackViewState();
field.HeaderText = name; //<- here's reflected property name
field.SortExpression = name;
field.ReadOnly = fieldProperties.IsReadOnly;
field.DataType = fieldProperties.Type;
return field;
}
While System.Windows.Forms.DataGridView uses DisplayName if available:
public DataGridViewColumn[] GetCollectionOfBoundDataGridViewColumns()
{
...
ArrayList list = new ArrayList();
//props is a collection of PropertyDescriptors
for (int i = 0; i < this.props.Count; i++)
{
if (...)
{
DataGridViewColumn dataGridViewColumnFromType = GetDataGridViewColumnFromType(this.props[i].PropertyType);
...
dataGridViewColumnFromType.Name = this.props[i].Name;
dataGridViewColumnFromType.HeaderText = !string.IsNullOrEmpty(this.props[i].DisplayName) ? this.props[i].DisplayName : this.props[i].Name;
}
}
DataGridViewColumn[] array = new DataGridViewColumn[list.Count];
list.CopyTo(array);
return array;
}
Unfortunately, while you can override the CreateAutoGeneratedColumn, neither the missing DisplayName nor underlying property descriptor gets passed, and you can't override CreateAutoGeneratedColumns (although you could CreateColumns).
This means you'd have to iterate over reflected properties yourself and in some other place.

If all you care about is the header text in GridView, just use the HeaderText property of each field you bind. If you're autogenerating the columns, you just set the HeaderText after you've bound the GridView.
If you want a GridView that takes into account some attribute you placed on the properties of your bound class, I believe you'll need to create your own GridView.
I may be wrong, but I've not seen any ASP.NET Grid from control vendors (at least Telerik , Janus Systems and Infragistics) do that. If you do it, maybe sell the idea to them.

Are you using .net4, what you need to do is to set enabledynamicdata on the grid view to true.

You can do it now on asp.net mvc2. It works just like that

Related

Property to check whether a row in grid view has been modified

Is there a simple property or method to check whether a row changed or column value has been changed in my grid view. I also want to get the index of modified/changed row
You can add it to the gridview like this
<asp:GridView Name="gridview1" OnRowUpdating="GridViewUpdateEventHandler" />
If I remember correctly there is an abundance of tutorials for gridviews and how to manipulate data.
No, there is no simple property for that. But...
Here is a method for that on MSDN
You'll have to modify it for your data and your control names to verify, but it's all there, straight from the keyboard of Microsoft.
protected bool IsRowModified(GridViewRow r)
{
int currentID;
string currentLastName;
string currentFirstName;
currentID = Convert.ToInt32(GridView1.DataKeys[r.RowIndex].Value);
currentLastName = ((TextBox)r.FindControl("LastNameTextBox")).Text;
currentFirstName = ((TextBox)r.FindControl("FirstNameTextBox")).Text;
System.Data.DataRow row =
originalDataTable.Select(String.Format("EmployeeID = {0}", currentID))[0];
if (!currentLastName.Equals(row["LastName"].ToString())) { return true; }
if (!currentFirstName.Equals(row["FirstName"].ToString())) { return true; }
return false;
}

ASP Multiselect listbox separator

I have encountered a problem and I didn't manage to find any soultions yet. Let me simplify things a bit.
I have 2 forms, the first contains an ASP ListBox with multi select mode enabled. I submit the form and in the other form I use just for testing purposes this snippet of code:
protected void Page_Load(object sender, EventArgs e)
{
foreach (string formKey in Request.Form.AllKeys)
{
if (formKey != null)
{
if (formKey.Equals("ctl00$MainContent$ListBox1"))
Label1.Text = Request.Form[formKey];
}
}
}
The problems is that the values that come from the listbox (the values that i selected in the previous form) are separated by "," for ex. "test1,test2,test3". How can i change this separator to "$" for example? I need to change it because the actual values may contain "," and i don't manualy feed them to the listbox.
I can't use any other mode of transfering this values between the form because the entire application uses this model. The values that i get are then sent to a workflow where there will be manipulated and in the workflow i need to know where each listbox item starts and ends so it must be an unique separator.
Any help is apreciated! Thank you very much
Thank you MatteKarla but unfortunately this does not solve my problem. Yes, this is a good way of transfering the values from one form to another.
However i must use the method I described above with Request form keys because the listbox is one of many others "parameters" that are generated at runtime and have their values sent to a workflow method that takes this values. And i can't afford to change that in my application.
My problem is that coma (",") separator is used by default with a multiselect listbox.
I thought that there maybe is a method to change that separator from coma to another char because the coma can also be included in the value itself and this will create confusion.
As i said if i select three values test1, test2 and test3, the result with my method will be a string looking like "test1,test2,test3". However a "test1$test2$test3" would be much better.
But I'm affraid that changing this default separator is not possbile. I must think at a method to overcome this problem like replacing before feeding the listbox all the intended coma from the values with some other char not to create confusion. But this is not a great way of doing it.
On your first page/form (First.aspx.cs) create a public property with the listbox:
public ListBox PostedListBox { get { return ListBox1; } }
Set the postback-url for the button to Second.aspx
Second page in the aspx-file after the #Page-directive add:
<%# PreviousPageType VirtualPath="~/First.aspx" %>
Then in Form_Load on Second.aspx.cs you can extract the values:
if (PreviousPage != null)
{
ListBox postedListbox = PreviousPage.PostedListBox;
foreach (var index in postedListbox.GetSelectedIndices())
{
var itemText = postedListbox.Items[index].Text;
}
}
Or you could just try to locate the control by using:
if (PreviousPage != null)
{
var control = PreviousPage.FindControl("ListBox1") as ListBox;
}
Third Edit:
You could use GetValues:
Request.Form.GetValues("ctl00$MainContent$ListBox1");
returns a string array containing each of the selected items.

How to resize columns of DataGrid bound to List<T>, not DataSet?

I'm trying to use a System.Windows.Forms.DataGrid control in my Compact Framework 3.5 Window Mobile Professional 6 SDK based project to show some properties of objects of type Something by binding the DataGrid to a List<SomethingWrapper> instance like this:
public class SomethingWrapper {
private Something data;
public SomethingWrapper(Something data) { this.data = data; }
public string Column1 { get { /* string from this.data */ } }
public string Column2 { get { /* string from this.data */ } }
}
public class SomethingList : List<SomethingWrapper> {
public SomethingList(IEnumerable<Something> items) {
foreach (var item in items) Add(new SomethingWrapper(item));
Sort((a, b) => a.Column2.CompareTo(b.Column2);
}
}
/* ... */
IEnumerable<Something> dataToShow = /* assume this is filled correctly */
SomethingDataGrid.DataSource = new SomethingList(dataToShow);
This seems to work fine: the correct data is shown in the grid with two columns called Column1 and Column2 and sorted on the second column. I want this to be a readonly view of this data, so all is fine.
However, I would like to set column widths and cannot seem to get this to work...
Have tried to obvious: creating TableStyle, creating textbox column style instance per column, adding it to the TableStyle and setting SomethingDataGrid.TableStyle to resulting table style. (This is from memory, or I would also show the exact code I'm using. If needed, I can add that to the question somewhere later today.)
Nothing changes however. I suspect this has something to do with the MappingName on the TableStyle object; all examples I could find yesterday evening seem to be for databinding a DataSet to the DataGrid and setting MappingName to the correct table name in the DataSet. Otherwise, the table style will not do what you expect, which is the behavior I'm seeing.
Question: am I looking in the correct place for a solution to my problem, and if so, what do I need to set TableStyle.MappingName to when binding to a List<T> to show properties of T...?
(Tried to check for possible duplicates, but was unable to find exact matches. Please correct me if I turn out to be wrong there.)
Ah, didn't look well enough after all: duplicate question found. Will try deriving from BindingList<T> and/or using a binding source so I can start calling BindingSource.GetListName(null) to get a MappingName. Hope this will help. If not, I'll be back...
You can do this by creating a DataGridTableStyle
Here is an extension method that I use:
public static void SetColumnStyles<T>(this DataGrid ctrl, T data, params ColumnStyle[] column) where T: class
{
var ts = new DataGridTableStyle();
ts.MappingName = data.GetType().Name;
foreach (var style in column)
{
ts.GridColumnStyles.AddColumn(style.Header, style.Column, style.Width);
}
ctrl.TableStyles.Clear();
ctrl.TableStyles.Add(ts);
}
Then I call it like this:
var newList = queriableData.ToList();
ProductEdit.DataSource = newList;
ProductEdit.SetColumnStyles(newList, new[]
{
new ColumnStyle("Name", 200),
new ColumnStyle("Manufacturer", 100),
new ColumnStyle("Size", 20)
});
where newList is a generic list of objects.

Accessing the object/row being edited in Dynamic Data

I'm modifying the "Edit.aspx" default page template used by ASP.NET Dynamic Data and adding some additional controls. I know that I can find the type of object being edited by looking at DetailsDataSource.GetTable().EntityType, but how can I see the actual object itself? Also, can I change the properties of the object and tell the data context to submit those changes?
Maybe you have found a solution already, however I'd like to share my expresience on this.
It turned out to be a great pita, but I've managed to obtain the editing row. I had to extract the DetailsDataSource WhereParameters and then create a query in runtime.
The code below works for tables with a single primary key. If you have compound keys, I guess, it will require modifications:
Parameter param = null;
foreach(object item in (DetailsDataSource.WhereParameters[0] as DynamicQueryStringParameter).GetWhereParameters(DetailsDataSource)) {
param = (Parameter)item;
break;
}
IQueryable query = DetailsDataSource.GetTable().GetQuery();
ParameterExpression lambdaArgument = Expression.Parameter(query.ElementType, "");
object paramValue = Convert.ChangeType(param.DefaultValue, param.Type);
Expression compareExpr = Expression.Equal(
Expression.Property(lambdaArgument, param.Name),
Expression.Constant(paramValue)
);
Expression lambda = Expression.Lambda(compareExpr, lambdaArgument);
Expression filteredQuery = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, query.Expression, lambda);
var WANTED = query.Provider.CreateQuery(filteredQuery).Cast<object>().FirstOrDefault<object>();
If it's a DD object you may be able to use FieldTemplateUserControl.FindFieldTemplate(controlId). Then if you need to you can cast it as an ITextControl to manipulate data.
Otherwise, try using this extension method to find the child control:
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
T found = startingControl.FindControl(id) as T;
if (found == null)
{
found = FindChildControl<T>(startingControl, id);
}
return found;
}
I found another solution, the other ones did not work.
In my case, I've copied Edit.aspx in /CustomPages/Devices/
Where Devices is the name of the table for which I want this custom behaviour.
Add this in Edit.aspx -> Page_Init()
DetailsDataSource.Selected += entityDataSource_Selected;
Add this in Edit.aspx :
protected void entityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
Device device = e.Results.Cast<Device>().First();
// you have the object/row being edited !
}
Just change Device to your own table name.

Accessing Row Data In Telerik RadGrid (Server Side)

Ive no problems using Javascript to read the rows of a telerik radgrid component im using however I can seem to find anyway to access the row data server side when a postback occurs. Ive spent ages looking for solution but no luck.
Any pointers would be greatly appreciated.
Tony
You might want to look at the DataKeyValues property of the OwnerTableView object, which will let you access a collection of values that represent the fields in a given row. I use it during the EditCommand event handler, since a user of my site is directed to an edit page if they click on the link to edit a row in the grid, and I need to pass along certain info about the given row in the query string.
If this turns out to be what you need, you'll also need to define which fields should be made available through this property. To do that, look at the MasterTableView.DataKeyNames property in the property sheet for the grid. You basically specify a comma-delimited list of field names.
The server-side is the easy part:
GridItemCollection gridRows = TestGrid.Items;
foreach (GridDataItem data in gridRows)
{
ItemClass obj = (ItemClass)data.DataItem;
}
It's the client side part that I don't know! :[
private Int32 GetID()
{
foreach (Telerik.Web.UI.GridDataItem dataItem in radGrid.MasterTableView.Items)
{
if (dataItem.Selected == true)
{
Int32 ID = (Int32)dataItem.GetDataKeyValue("ID");
return ID;
}
}
throw new ArgumentNullException("Id Not found");
}
This is the one that works for me and uses the RadGrid.SelectedItems collection.
protected void LinkButton1_Click(object sender, EventArgs e)
{
List<Guid> OrderIdList = new List<Guid>();
foreach (GridDataItem OrderItem in this.RadGrid1.SelectedItems)
{
OrderIdList.Add(new Guid(OrderItem.GetDataKeyValue("OrderId").ToString()));
}
}
If you correctly created your controls in markup or page init for dynamic controls, then the RadGrid will properly restore state.
You can access the initial values that were loaded from the data source like this example below, provided you told the table view in question to keep the columns around in the data keys.
protected T GetInitialGridData<T>(GridDataItem item, string uniqueColumnName) {
item.ThrowIfNull("item");
uniqueColumnName.ThrowIfNullOrEmpty("uniqueColumnName");
return (T)item.OwnerTableView.DataKeyValues(gridItem.ItemIndex)(columnName);
}
If you are using a dynamic custom template column, and need to get to any values that may now be in their states, you can use:
protected string GetCustomTextBoxValue(GridDataItem item, string controlID) {
item.ThrowIfNull("item");
controlID.ThrowIfNullOrTrimmedEmpty("controlID");
return ((TextBox)item.FindControl(controlID)).Text;
}
private Int32 GetID()
{
foreach (Telerik.Web.UI.GridDataItem dataItem in radGrid.MasterTableView.Items)
{
if (dataItem.Selected == true)
{
// Int32 ID = (Int32)dataItem.GetDataKeyValue("ID");
Int32 ID =Convert.ToInt32(dataItem.GetDataKeyValue("ID"));
return ID;
}
}
}
//this will work

Resources