getting attributes from aspx-page - asp.net

i have an aspx-page which contains a detailsview.
this detailsview contains one or more templated-fields.
what i need is a additional attribute (or metadata information) to determite the bound datafield.
some thing like that would be nice (simplified):
<asp:DetailsView>
<fields>
<TemplateField DataField="DataField1">
...
</TemplateField>
</fields>
</asp:DetailsView>
is it possible to get attribute "DataField" ?
otherwise i will subclassing TemplateField and add a property :)

I haven't done that for a while, but I seem to remember if you add a public set/get "DataField" property to the TemplateField class, ASP.NET should automatically initialize it with the value you pass in the attribute.

i thought subclassing of TemplateField will do the job:
[AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Minimal)]
[DefaultProperty("DataField")]
public class DataTemplateField : TemplateField
{
private String _dataField;
public String DataField
{
get {
return _dataField;
}
set {
_dataField = value;
}
}
}
now u can use this field in detailsview like this
<Fields>
<dvt:DataTemplateField HeaderText="Feld1" DataField="DIS">
<ItemTemplate>
<asp:Button runat="server" Text="Button" />
</ItemTemplate>
</dvt:DataTemplateField>
</Fields>
and get that data
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
foreach(DetailsViewRow row in DetailsView1.Rows)
{
DataControlFieldCell cell = (DataControlFieldCell)row.Cells[1];
if (cell.ContainingField is DataTemplateField)
{
var field = (DataTemplateField)cell.ContainingField;
cell.Enabled = !field.DataField.Equals(fieldToDisable);
}
}
}

Related

How do I get a reference to a telerik:GridTemplateColumn from a child control?

Simplified code from page:
<%# Page Language="C#" etc... %>
<%# Register src="~/controls/RequiredField.ascx" tagname="rf" tagprefix="custom" %>
<telerik:RadGrid runat="server">
<MasterTableView>
<Columns>
<telerik:GridTemplateColumn DataField="Name" HeaderText="Name" SortExpression="Name">
<ItemTemplate><%#Eval("Name")%></ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="NewName" runat="server" Text='<%#Bind("Name")%>'></asp:TextBox>
<custom:rf runat="server" />
</EditItemTemplate>
</telerik:GridTemplateColumn>
</Columns>
</MasterTableView>
</telerik:RadGrid>
In my control, I want to check if the parent is an EditItemTemplate and then set a property of the telerik:GridTemplateColumn. For example:
public partial class controls_RequiredField : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (this.Parent is Telerik.Web.UI.GridEditFormItem.EditFormTableCell)
{
// how do I get a reference to 'Telerik.Web.UI.GridTemplateColumn' (or any other object that lets me set the header text)
((Telerik.Web.UI.GridTemplateColumn)this.Parent.Parent).EditFormHeaderTextFormat = "{0}:" + RequiredText.Text;
RequiredText.Visible = false;
}
}
}
I don't have the telerik:RadGrid but it is pretty similar to the MS GridView, so I was able to test your issue using asp:GridView (both inherit from CompositeDataBoundControl Class (System.Web.UI.WebControls))
since your custom control is located in the EditItemTemplate your RequiredField control's Page_Load event will not fire until the RadGrid switches to edit mode so you should be able to drop the if (this.Parent is...) check as you'll know the grid is in edit mode.
So with the custom control's page load indicating the grid is in edit mode you can set the HeaderText of the GridTemplateColumn by doing something like:
if (typeof(DataControlFieldCell) == Parent.GetType())
{
((DataControlFieldCell)this.Parent).ContainingField.HeaderText = "Your Custom Heading"; // Or += if appending
}
Well this is the code I'm currently using that works:
protected void Page_Init(object sender, EventArgs e)
{
if (this.Parent is GridEditFormItem.EditFormTableCell)
{
GridEditFormItem.EditFormTableCell parentCell = (GridEditFormItem.EditFormTableCell)this.Parent;
string col = parentCell.ColumnName;
// ridiculous:
Control parentFormItem = this.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent.Parent;
if (parentFormItem is GridItem)
{
GridItem gi = (GridItem)parentFormItem;
GridColumn parentColumn = gi.OwnerTableView.Columns.FindByUniqueNameSafe(col);
if (parentColumn != null)
{
parentColumn.EditFormHeaderTextFormat = "{0}:" + RequiredText.Text;
RequiredText.Visible = false;
}
}
}
}
But having to cycle up through all those .Parents makes me uneasy.

ListView + ObjectDataSource SelectMethod called twice when EnableViewState="false"

Note: This question has been completely modified now that I have a simpler example.
I have set up a sample page which only has a ListView and ObjectDataSource. The first time the page comes up (!IsPostBack), my GetList method is called once. After paging (IsPostBack), the GetList method is called twice--the first time with the old paging values and the second time with the new values.
If I set EnableViewState="true" on the ListView, then the GetList method is only called once. It seems to me that the ListView wants an "initial state", which it either gets from ViewState or by re-running the method.
Is there any way to disable ViewState on the ListView and also prevent SelectMethod from being called twice?
ASPX page:
<asp:ListView ID="TestListView" runat="server" DataSourceID="ODS" EnableViewState="false">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server" />
<asp:DataPager ID="TestPager" runat="server" PageSize="10">
<Fields>
<asp:NumericPagerField />
</Fields>
</asp:DataPager>
</LayoutTemplate>
<ItemTemplate>
<div><%# Eval("Title") %></div>
</ItemTemplate>
</asp:ListView>
<asp:ObjectDataSource ID="ODS" runat="server" SelectMethod="GetList" SelectCountMethod="GetListCount"
TypeName="Website.Test" EnablePaging="true" />
ASPX code-behind:
namespace Website
{
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
public IList<DataItem> GetList(int maximumRows, int startRowIndex)
{
return GetListEnumerable().Skip(startRowIndex).Take(maximumRows).ToList();
}
public IEnumerable<DataItem> GetListEnumerable()
{
for (int i = 0; i < 100; i++)
{
yield return new DataItem { Title = i.ToString() };
}
}
public int GetListCount()
{
return 100;
}
}
public class DataItem
{
public string Title { get; set; }
}
}
Either turn ODS caching on.
<asp:ObjectDataSource ID="ODS" ... EnableCaching="true" />
This way the GetList will be called only when new data is needed. Post backs to pages that already had data retrieved will use the cached version and not call the GetList.
Or move your DataPager out of the ListView and set the PagedControlID property.
Actually you should be using the OnSelecting event.
What happens is that ObjectDataSource calls the method SelectMethod twice
First time it gets the data.
Next time it gets the count.
So I think you have to implement the OnSelecting event
<asp:ObjectDataSource ID="ODS" runat="server" SelectMethod="GetList" SelectCountMethod="GetListCount"
OnSelecting="ods_Selecting">
TypeName="Website.Test" EnablePaging="true" />
and then cancel the event when the ObjectDataSource tries to call the count method.
protected void ods_Selecting(object sender,
ObjectDataSourceSelectingEventArgs e)
{
if (e.ExecutingSelectCount)
{
//Cancel the event
return;
}
}
You can look for full implementation as mentioned in the link below
http://www.unboxedsolutions.com/sean/archive/2005/12/28/818.aspx
Hope this helps.
I had a similar problem where it worked different depending on browser. IE one way and all other browsers one way.. Might not be the same issue as you have.
I solved it this way:
protected void DropDownDataBound(object sender, EventArgs e)
{
// Issue with IE - Disable ViewState for IE browsers otherwhise the dropdown will render empty.
DropDownList DDL = (DropDownList)sender;
if (Request.Browser.Browser.Equals("IE", StringComparison.CurrentCultureIgnoreCase))
DDL.ViewStateMode = System.Web.UI.ViewStateMode.Disabled;
else
DDL.ViewStateMode = System.Web.UI.ViewStateMode.Inherit;
}

ASP.Net GridView GridViewDeleteEventArgs.Keys empty

I have following Gridview:
<asp:GridView ID="GridView1" runat="server" CssClass="table" DataKeyNames="groupId"
DataSource="<%# dsUserGroupsSelected %>" DataMember="Group" etc....>
and after firing RowDeleting event handler:
protected void GridView1_RowDeleting(object sender, GridViewDeleteEventArgs e)
e.Keys is empty. Moreover, in runtime if I check
dsUserGroupsSelected.Group.PrimaryKey
it is poulated with:
{System.Data.DataColumn[1]}
[0]: {groupId}
so it's really odd to me. Am I missing something? I have this kind of a workaround:
int groupId = (int)GridView1.DataKeys[e.RowIndex].Value;
which will work just fine, but I just can't get it why e.Keys (and e.Values) would be empty!? Any ideas?
It looks like this behaviour is intentional.
From http://forums.asp.net/p/1050092/2128091.aspx
Looking in Reflector at Gridview.HandleDelete(), it appears that
e.Keys and e.Values are only populated if
gridview.IsBoundUsingDataSourceID. That is, if you set the DataSource
in code then none of this will work. Good one, Microsoft! Might have
been useful to mention that in the help perhaps??!! Lachlan
Edit:
I ended up making my own data objects and put them in the app_code folder
ex.
public class CustomDataViews
{
public class FileQuery
{
public class File
{
public DateTime CreatedDate { get; set; }
public string FileName { get; set; }
public string Path { get; set; }
public void Delete() { }
}
public ArrayList GetFiles()
{
System.Collections.ArrayList files = new ArrayList();
System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(HttpContext.Current.Server.MapPath("~/UserUpload/"));
foreach (System.IO.FileInfo fi in (from a in di.GetFiles() orderby a.CreationTime descending select a))
{
File myFile = new File();
myFile.CreatedDate = fi.CreationTime;
myFile.FileName = fi.Name;
myFile.Path = "/VACWeb/UserUpload/" + fi.Name;
files.Add(myFile);
}
return files;
}
public void Delete(string FileName)
{
if (FileName != null)
{
string path = HttpContext.Current.Server.MapPath("~/UserUpload/") + FileName;
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
}
}
}
}
aspx
<asp:GridView ID="gvFiles" runat="server" AutoGenerateColumns="False" DataKeyNames="FileName"
DataSourceID="ods1">
<Columns>
<cc:ExtendedCommandField DeleteConfirmationText="Are you sure you wish to delete this file?"
DeleteText="Delete" ShowDeleteButton="true" />
<asp:BoundField DataField="CreatedDate" HeaderText="Created Date" DataFormatString="{0:MM/dd/yyyy}" />
<asp:BoundField DataField="FileName" HeaderText="File Name" />
<asp:ImageField DataImageUrlField="Path" AlternateText="No Image" HeaderText="Image Preview"
ControlStyle-Width="100px">
<ControlStyle Width="100px" />
</asp:ImageField>
<asp:BoundField DataField="Path" HeaderText="Path" />
<asp:HyperLinkField DataNavigateUrlFields="Path" DataTextField="FileName" HeaderText="Link" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ods1" runat="server" DeleteMethod="Delete" SelectMethod="GetFiles"
TypeName="CustomDataViews+FileQuery">
<DeleteParameters>
<asp:Parameter Name="FileName" Type="String" />
</DeleteParameters>
</asp:ObjectDataSource>
Simple! ASP is a big piece of .... and GridView is a small piece in the big peace. Have the same problem, and while the workaround is ok for deleting, updating becomes really interesting... The actual problem is it seems that for no good or apparent reason a looooooooot of the functionality of GridView is missing if the DataSource is not a DataSourceControl: Like filling the keys & values properties in the eventargs. Enjoy! Viva Microsoft!
Is it possible you're programatically sorting your gridview in your Page_Load method? If so, try moving the sort into the Page_Init method, and see if that fixes the problem.
Apparently, the GridViewDeleteEventArgs.Keys property only works if you set the GridView's DataSource by setting the DataSourceID property -- i.e. setting the DataSource property and then manually calling DataBind() leaves the Keys property (and the Values property as well) empty.
Source: http://forums.asp.net/t/1050092.aspx

ASP.NET DataGrid and custom paging

I'm trying to implement a DataGrid in ASP.NET, and want to achieve custom paging so that I don't have to provide all the data in one go. I've spent several hours researching on the internet, but haven't found anything useful.
When I view the page I see the first set of results in the grid, with the previous link disabled. When I click next however, I once again see the first page of the grid with the previous link disabled. When debugging the code I ascertained that the MyGrid_PageIndexChanged() event handler is never called.
I've included my simplified code below. I've changed variable names and omited methods to focus on the datagrid paging issue.
In the ASPX file:
<asp:DataGrid ID="myGrid" runat="server" GridLines="None" UseAccessibleHeader="true" AutoGenerateColumns="false" AllowPaging="true" AllowCustomPaging="true" PageIndexChanged="MyGrid_PageIndexChanged">
<PagerStyle Mode="NextPrev" NextPageText="Next >" PrevPageText="< Previous" />
<Columns>
<asp:BoundColumn HeaderText="Title" DataField="Name" />
<asp:BoundColumn HeaderText="Date" DataField="Date" />
</Columns>
</asp:DataGrid>
And in the CS file:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
myGrid.PageSize = 20;
myGrid.VirtualItemCount = GetNumItems();
BindMyGrid();
}
}
protected void MyGrid_PageIndexChanged(object sender, DataGridPageChangedEventArgs e)
{
myGrid.CurrentPageIndex = e.NewPageIndex;
BindMyGrid();
}
private int GetNumItems()
{
return 500;
}
private void BindMyGrid()
{
Data[] array = GetDataFromInternetSomehow();
this.myGrid.DataSource = array;
this.myGrid.DataBind();
}
private class Data
{
public string Date { get; set; }
public string Name { get; set; }
}
Any thoughts on this would be much appreciated.
There is an error in your ASPX: to wire up the PageIndexChanged event handler use the property OnPageIndexChanged (not PageIndexChanged as in your code):
<asp:DataGrid ID="myGrid" runat="server"
OnPageIndexChanged="MyGrid_PageIndexChanged" /// <--- here's the error
...
Then, if you have AllowCustomPaging="true", you must ensure that the GetDataFromInternetSomehow() method will only return the data for the currently selected page, e.g. pass the current page to the method and return only the corresponding data:
GetDataFromInternetSomehow(e.NewPageIndex);
Otherwise, disable custom paging and it will just work (but all data will be loaded everytime).

Bind ASP.NET DropDownList DataTextField to method?

Is there anyway to have items in an ASP.NET DropDownList have either their Text or Value bound to a method on the source rather than a property?
This is my solution:
<asp:DropDownList ID="dropDownList" runat="server" DataSourceID="dataSource" DataValueField="DataValueField" DataTextField="DataTextField" />
<asp:ObjectDataSource ID="dataSource" runat="server" SelectMethod="SelectForDataSource" TypeName="CategoryDao" />
public IEnumerable<object> SelectForDataSource()
{
return _repository.Search().Select(x => new{
DataValueField = x.CategoryId,
DataTextField = x.ToString() // Here is the trick!
}).Cast<object>();
}
Here's 2 examples for binding a dropdown in ASP.net from a class
Your aspx page
<asp:DropDownList ID="DropDownListJour1" runat="server">
</asp:DropDownList>
<br />
<asp:DropDownList ID="DropDownListJour2" runat="server">
</asp:DropDownList>
Your aspx.cs page
protected void Page_Load(object sender, EventArgs e)
{
//Exemple with value different same as text (dropdown)
DropDownListJour1.DataSource = jour.ListSameValueText();
DropDownListJour1.DataBind();
//Exemple with value different of text (dropdown)
DropDownListJour2.DataSource = jour.ListDifferentValueText();
DropDownListJour2.DataValueField = "Key";
DropDownListJour2.DataTextField = "Value";
DropDownListJour2.DataBind();
}
Your jour.cs class (jour.cs)
public class jour
{
public static string[] ListSameValueText()
{
string[] myarray = {"a","b","c","d","e"} ;
return myarray;
}
public static Dictionary<int, string> ListDifferentValueText()
{
var joursem2 = new Dictionary<int, string>();
joursem2.Add(1, "Lundi");
joursem2.Add(2, "Mardi");
joursem2.Add(3, "Mercredi");
joursem2.Add(4, "Jeudi");
joursem2.Add(5, "Vendredi");
return joursem2;
}
}
The only way to do it is to handle the Databinding event of the DropDownList, call the method and set the values in the DropDownList item yourself.
Sometimes I need to use Navigation Properties as DataTextField, like ("User.Address.Description"), so I decided to create a simple control that derives from DropDownList.
I also implemented an ItemDataBound Event that can help as well.
public class RTIDropDownList : DropDownList
{
public delegate void ItemDataBoundDelegate( ListItem item, object dataRow );
[Description( "ItemDataBound Event" )]
public event ItemDataBoundDelegate ItemDataBound;
protected override void PerformDataBinding( IEnumerable dataSource )
{
if ( dataSource != null )
{
if ( !AppendDataBoundItems )
this.Items.Clear();
IEnumerator e = dataSource.GetEnumerator();
while ( e.MoveNext() )
{
object row = e.Current;
var item = new ListItem( DataBinder.Eval( row, DataTextField, DataTextFormatString ).ToString(), DataBinder.Eval( row, DataValueField ).ToString() );
this.Items.Add( item );
if ( ItemDataBound != null ) //
ItemDataBound( item, row );
}
}
}
}
Declaratively:
<asp:DropDownList ID="ddlType" runat="server" Width="250px" AppendDataBoundItems="true" DataSourceID="dsTypeList" DataTextField="Description" DataValueField="ID">
<asp:ListItem Value="0">All Categories</asp:ListItem>
</asp:DropDownList><br />
<asp:ObjectDataSource ID="dsTypeList" runat="server" DataObjectTypeName="MyType" SelectMethod="GetList" TypeName="MyTypeManager">
</asp:ObjectDataSource>
The above binds to a method that returns a generic list, but you could also bind to a method that returns a DataReader. You could also create your dataSource in code.

Resources