asp.net datasource instantiate class - asp.net

I have a static method that takes a parameter and returns a class. the class has a ReadOnlyCollection Property that i'd like to display in a asp:repeater. Is there a way to do this using LinqDataSource or ObjectDataSource? I got pretty close with ObjectDataSource, but since the method is returning a single class object, I couldn't get me repeater to bind to the Property.. Here's what I did:
ClassName: ClassName
StaticMethod: StaticMethod(ParamName)
ReadOnlyCollection: ClassName.Collection
<asp:objectdatasource
runat="server"
id="myData"
selectmethod="StaticMethod"
typename="ClassName"
>
<selectparameters>
<asp:parameter name="ParamName" defaultvalue="Value" />
</selectparameters>
</asp:objectdatasource>
<asp:repeater runat="server" datasourceid="myData">
<itemtemplate>
<%# Container.DataItem %>
</itemtemplate>
</asp:repeater>
So, This only returns the readonly collection object, not each item as i'd like.
Is this possible without have actual code to instantiate the object?

If you're only concerned with displaying data in your collection you could add another static method that returns your objects ReadOnlyCollection and bind to that. Alternatively you can ditch the ObjectDataSource and do it in code, something like:
var myObj = ClassName.StaticMethod(someParam);
MyRepeater.DataSource = myObj.Collection;
MyRepeater.DataBind();
If you need to display both data in your class and collection, then you can add another Repeater to the ItemTemplate:
<asp:objectdatasource runat="server" id="myData"
selectmethod="StaticMethod" typename="ClassName">
<selectparameters>
<asp:parameter name="ParamName" defaultvalue="Value" />
</selectparameters>
</asp:objectdatasource>
<asp:Repeater runat="server" datasourceid="myData" OnItemDataBound="Rep_ItemDataBound">
<ItemTemplate>
<%# Eval("SomeProperty") %>
<ul>
<asp:Repeater id="RepCollection" runat="server">
<ItemTemplate>
<li><%# Eval("SomeCollectionProperty") %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
</ItemTemplate>
</asp:Repeater>
The ItemDataBound method would look something like:
protected void Rep_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item)
{
var dataItem = (ClassName)e.Item.DataItem;
var innerRepeater = (Repeater)e.Item.FindControl("RepCollection");
innerRepeater.DataSource = dataItem.Collection;
innerRepeater.DataBind();
}
}

Related

how to set control's id dynamically in asp.net

how can is set id dynamic with Eval method and setting the id from sql database to a controller , like this
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="articlesqlfetch">
<ItemTemplate>
<strong > <%# Eval("title") %> </strong>
<br>
<-! this is the line ->
<asp:HyperLink ID="_<%# Eval("id") %>" runat="server">قراءة المزيد</asp:HyperLink>
</ItemTemplate>
when do this it give me a Parser Error
Using Eval() to provide dynamically generated ID is not allowed because you cannot bind to ID property of server controls, hence this code is wrong:
<asp:HyperLink ID="_<%# Eval("id") %>" runat="server">some text</asp:HyperLink>
Instead, use ItemDatabound event for repeater control like this (assumed your ID is auto-generated identity field):
Markup (ASPX)
<asp:Repeater ID="Repeater1" runat="server" DataSourceID="articlesqlfetch"
OnItemDataBound="Repeater1_ItemDataBound">
<ItemTemplate>
<%-- repeater contents --%>
<asp:HyperLink ID="Hyperlink1" runat="server">some text</asp:HyperLink>
</ItemTemplate>
</asp:Repeater>
Code-behind
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
HyperLink hyperlink = e.Item.FindControl("Hyperlink1") as HyperLink;
if (hyperlink != null)
{
hyperlink.ID = "_" + (e.Item.ItemIndex + 1).ToString(); // set ID from bound data
hyperlink.ClientIDMode = ClientIDMode.Static;
hyperlink.NavigateUrl = "some/uri/here"; // optional
// other stuff
}
}

Passing CommandArguement to LinkButton from variable

I have seen many resources on SO that say that I can use following syntax to pass value to CommandArguement of `LinkButton'
<%forearch(var comment in Comments){%>
<asp:LinkButton ID="del" CommandArguement='<%= comment.CommentId%>' onCommand="delete_click" Text="Delete"/>
<%}%>
But when I write this in my ascx file and click on the link the value passed to command argument is "<%=comment.CommentId%>" instead of commentId itself. Please guide what am I doing wrong?
Edit 1
based on answers and comments, I have moved to use repeater instead of foreach and plain code. Here is the code I have come up with
<asp:Repeater ID="commRepeater" SelectMethod="GetPageComments" runat="server">
<ItemTemplate>
<p>
<%#Eval("Comment") %>
<%if(Page.User.Identity.IsAuthenticated && Page.User.Identity.GetUserId() == Eval("UserId")){ %>
<span>
<asp:LinkButton Text="Edit" runat="server" ID="EditLink" CommandArgument='<%#Eval("CommentId")%>' OnClick="Update_Comment" />
<asp:LinkButton Text="Delete" runat="server" ID="DeleteLink" CommandArgument='<%#Eval("CommentId")%>' OnClientClick="if (!confirm('Are you sure you want delete?')) return false;" OnCommand="Delete_Comment" />
</span>
<%} %>
</p>
</ItemTemplate> </asp:Repeater>
you can see that I am trying to show the edit and delete links if user is logged in and his Id matches with user who commented but it tells me that I can on use Eval in databound controls. how would I hide/show edit/delete links conditionally within repeater
You could simply use codebehind, for example in Page_Load:
protected void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
del.CommandArgument = comment.CommentId;
}
}
Maybe a better approach would be to use the Comments-collection(which seems to be a list or array of a custom class) as DataSource of a Repeater(or other web-databound control). Then you can add the LinkButtons to the Itemtemplate.
You can then either use ItemCreated or ItemDataBound events of the repeater in codebehind or inline ASP.NET tags to bind the CommandArgument.
For example:
CommandArguement='<%# DataBinder.Eval( Container.DataItem, "CommentId" ) %>'
What you are doing currently is not recommended and is highly error prone. You can easily achieve this with ASP.NET Repeater control like this:-
<asp:Repeater ID="MyRepeater" runat="server">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Eval("CommentId") %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
In Page_Load simply bind it:-
if (!Page.IsPostBack)
{
MyRepeater.DataSource = CommentsRepository();
MyRepeater.DataBind();
}
Or Else if you are have ASP.NET 4.5 then use strongly type Data Bound controls like this:-
<asp:Repeater ID="MyRepeater" runat="server" ItemType="MyNamespace.Comment"
SelectMethod="MyRepeater_GetData">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Item.CommentId %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
And you method in code behind should be something like this(just for Demo):-
public IEnumerable<MyNamespace.Comment> MyRepeater_GetData()
{
return new List<Comment>
{
new Comment { CommentId =1, Name= "foo"},
new Comment { CommentId =2, Name= "bar"},
};
}

ASP.NET Linkbutton not getting dynamic value for commandargument value

<%
foreach (training t in traininglist)
{
%>
<tr>
<td><%=t.TrainingId%></td>
<td><%=t.TrainingName%></td>
<td>
<asp:LinkButton runat="server" ID="EditBtn"
Text="Edit" OnCommand="editbtn_OnCommand"
CommandArgument='<%# t.TrainingId %>' CommandName="edit" />
</td>
</tr>
<% } %>
where,
training is the class and traininglist is List<training> defined in Page_Load() function in codebehind.
I am trying to call the
public void editbtn_OnCommand(object sender, CommandEventArgs e)
{
String myeid = e.CommandArgument.ToString();
....
}
Here, myeid is not getting value but always shows <%# t.TrainingId %>
i have already tried all other options like <%: t.TrainingId %> or <%=t.TrainingId %>
The output of Tag "<%= %>" is more likely similar to use Response.Write in your code. so these tags are used to display the value to the response object.
That's why,as per my understanding, You can't used these tags to set commandargument property of controls unless you are using DataBinding. If you are using DataBinding then these tags "<%= %>" are used to set the property of controls.
Because you are here looping through each item in list on html table, my suggestion is to use GridView or Repeater and then Bind through your List Object. if you are using this way, you can get rid of unwanted formatting issues of html tables also.
Refer http://msdn.microsoft.com/en-us/library/6dwsdcf5(VS.71).aspx
If you want to use repeater then you can use these specific tags, and this should be your code(not actual code, just sample one)
<asp:Repeater id="myRepeater" runat="server" >
<ItemTemplate>
<div>
<asp:LinkButton runat="server" id="EditBtn" CommandName="edit"
CommandArgument="<%#Container.DataItem.TrainingId %>" Text="Edit"
OnCommand="editbtn_OnCommand" />
</div>
</ItemTemplate>
</asp:Repeater>

PostBack DataBind error: "Ensure that the control is added to the page before calling DataBind."

I have a program that allows the user to use a few dropdowns to pick a topic and attribute, then the data are pulled that match on both of those conditions. In the gridview are a lot of templatefields use textboxes for instant editing (a submit button saves all changes) as well as a template with a dropdown bound to a parameter. This was all working hunky-dory for quite a while.
Then, we changed some of the data in the tables (keeping all the same field names) and now the page loads perfectly fine on launch but then as soon as you select something different in any of the drilldown dropdowns the page fails. I get an error saying
"The DropDownList control 'TagDDL' does not have a naming container.
Ensure that the control is added to the page before calling DataBind."
(TagDDL is the dropdown in the templatefield in gridview). If I simply remove this templatefield, I get a similar (though different) error on a hyperlinkfield, removing this gives me an error in a boundfield, so obviously it's not tied to any one thing.
My idea is that it has something to do with how databinding works on post-back, since the page loads perfectly initially, the dropdowns have 'Enable PostBack' and the error messages refer to DataBind. Any ideas?
The SqlDataSource that builds Gridview (leaving out the drilldown dropdowns for now)
<asp:SqlDataSource ID="MasterTable" runat="server"
ConnectionString="<%$ ConnectionStrings:spvConnectionString %>"
SelectCommand="exec pmtv2.maintable_display 1, #IPG_Assigned, #CompetitorName, #enterprise_zone, #Banner, #BrandName"
<SelectParameters>
<asp:ControlParameter ControlID="ChooseBanner" Name="Banner" PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="ChooseIPGs" Name="IPG_Assigned" PropertyName="SelectedValue" Type="Int32" />
<asp:ControlParameter ControlID="ChooseBrands" Name="BrandName" PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="ChooseComps" Name="CompetitorName" PropertyName="SelectedValue" Type="String" />
<asp:ControlParameter ControlID="ChooseZone" Name="enterprise_zone" PropertyName="SelectedValue" Type="Int32" />
</SelectParameters>
<div id="MasterDiv" style="width:90%">
<asp:GridView ID="MasterDisplay" runat="server"
AllowSorting="True" AutoGenerateColumns="False"
DataKeyNames="productKey,banner,enterprise_zone,userID" DataSourceID="MasterTable"
OnRowDataBound="MasterDisplay_RowDataBound"
OnSorting="MasterDisplay_Sorting"
class="mGrid" AlternatingRowStyle-CssClass="mGridAlt">
</AlternatingRowStyle>
<Columns>
<asp:TemplateField HeaderText="Description" SortExpression="productdescriptionlong">
<ItemTemplate>
<a href="javascript:openPopup('JustinPractice4.aspx?UPC=<%# Eval("UPC") %>
&banner=<%# Eval("banner") %>&enterprise_zone=<%# Eval("enterprise_zone") %>')"><%# Eval("productdescriptionlong")%></a>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="BrandName" HeaderText="Brand"
SortExpression="BrandName" />
<asp:TemplateField HeaderText="New Price" SortExpression="new_base_retail">
<ItemTemplate>
<asp:TextBox ID="RWNextPrice" runat="server"
Text='<%# Bind("new_base_retail", "{0:N2}") %>' Width="60px"
class="calculate" onchange="lineItemRipple(this)"
Visible='<%# ShowBox %>'></asp:TextBox>
<asp:Label ID="RNextPrice" runat="server" Text='<%# Eval("new_base_retail", "{0:c}") %>'
Visible='<%# ShowLabel %>'></asp:Label>
<asp:HiddenField ID="lineCode" runat="server" Value='<%# Eval("line_code") %>'/>
</ItemTemplate>
</asp:TemplateField>
<asp:ImageField DataImageURLField="unique_flags" HeaderText="Flags"
DataImageURLFormatString="Media/Images/{0}.png" SortExpression="unique_flags"/>
<asp:TemplateField HeaderText="Tag Type" SortExpression="tag_type">
<ItemTemplate>
<asp:DropDownList ID="TagDDL" runat="server"
DataSourceID="dimTags"
DataTextField="Tag_type_name"
DataValueField="Tag_type_name"
SelectedValue='<%#Bind("tag_type") %>'
visible='<%#ShowBox %>'>
</asp:DropDownList>
<asp:Label ID="TagR" runat="server"
Text='<%# Eval("tag_type") %>'
Visible='<%# ShowLabel %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:Button ID="Commit" runat="server" Text="Commit Changes" OnClick="Commit_Click"
class="button"/>
and the relevant code behind:
protected void Page_Load(object sender, EventArgs e) {
ErrorMsg.Text = "test45";
}
protected void MasterDisplay_RowDataBound(object sender, GridViewRowEventArgs e) {
DataSourceSelectArguments sr = new DataSourceSelectArguments();
DataView dv = (DataView)CheckForCommit.Select(sr);
if (dv.Count != 0) {
CommittedOrNot.Text = dv[0][0].ToString();
}
//pulling results from a SqlDataSource confirming presence of data
//calculations to maintain a running tally of certain fields for later use
}
protected void Commit_Click(Object sender, EventArgs e) {
string tagValue = "FLAG";
foreach (GridViewRow gvr in MasterDisplay.Rows) {
tagValue = ((DropDownList)gvr.FindControl("TagDDL")).SelectedValue;
MasterDisplay.UpdateRow(gvr.RowIndex, false);
} //for every row, update it
MasterDisplay.DataBind();
}
It was a simple error of trying to add to a DDL before I had actually pulled the data needed to bind it. Changing the order of things slightly did the trick
I am glad you found your answer. I had a similar issue on a UserControl (ascx) that was being loaded a run-time. I, too, had made a change to my data source and the corresponding sql data sources. (In my case, I was replacing the sql data sources with an entity model.)
What I found was that one of my controls would bind to the new data source (via the code behind) with no problems. The code looked as follows:
gridSomeData.DataSource = controller.GetListOfAssociatedParts();
gridSomeData.DataBind();
However, in the same method, the next section of code would fail when the DataBind() method was called. The code looked as follows:
drpDataList.DataSource = controller.GetListOfParts();
drpDataList.DataTextField = "PartID"
drpDataList.DataValueField = "PartKey"
drpDataList.DataBind();
It turned out, that when I removed the prior ASCX markup for the SqlDataSource objects, I failed to remove the reference in the DataSourceID attribute of the drop down control. So when I called the DataBind() method, the binding engine checked the attributes of the control, found a name DataSourceID, and immediately went looking for it in the control hierarchy of the UserControl. When the binding engine failed to find the object, it threw the exception "The DropDownList control [...] does not have a naming container..."
I will admit that this particular exception is somewhat misleading, as it is really the binder being confused over which instructions to follow for the data source (the code behind, or the markup in the ascx file).
I hope this helps with some perspective. :)

In a FormView, how to change the property of a Label in the ItemTemplate?

In ASP.NET, I have a FormView which is bound to an ObjectDataSource. The FormView has an ItemTemplate with a Delete button, and a Label. I'm handling the OnItemDeleted event of the FormView to detect if my business class throws an exception upon deletion. If an exception is detected, I change the text of the Label to whatever the exception message is.
Well, it's just not working.
I detect the Exception fine, but the Text of the Label never gets changed. When the page reloads, the default text stays. I have also tried to rebind the FormView with DataBind() after assigning the new Text, but it's not working either.
In a desperate attempt at tracking the problem, I've taken the Label out of the FormView and it's working fine.
What I am doing wrong?
ASPX page:
<asp:ObjectDataSource ID="MyObjectDataSource"
TypeName="MyScopeRepository"
SelectMethod="GetById"
DeleteMethod="Delete"
runat="server">
<SelectParameters>
<%-- The id param here is from a DropDownList, not included in the example for clarity. --%>
<asp:ControlParameter Name="id" Type="Int32" ControlID="MyDropDownList" PropertyName="SelectedValue" />
</SelectParameters>
<DeleteParameters>
<asp:Parameter Name="id" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
<asp:FormView ID="MyFormView" DataSourceID="MyObjectDataSource"
RenderOuterTable="false"
DataKeyNames="Id"
OnItemDeleted="MyFormViewItemDeleted"
runat="server">
<ItemTemplate>
<asp:Button CssClass="Button Small" Text="Delete" CommandName="Delete" runat="server" /><br />
<asp:Label ID="ErrorLabel" Text="Default text" runat="server" />
</ItemTemplate>
</asp:FormView>
Code-behind:
protected void MyFormViewItemDeleted(object sender, FormViewDeletedEventArgs e)
{
if (e.Exception != null && e.Exception.InnerException is RepositoryException)
{
Label errorLabel = (Label)MyFormView.FindControl("ErrorLabel");
errorLabel.Text = e.Exception.InnerException.Message;
e.ExceptionHandled = true;
// I also tried this to no avail.
//MyFormView.DataBind();
}
}
Thanks a lot!
EDIT: I've checked all events fired by the FormView when clicking the Delete button and here is what I got:
OnInit
OnItemCreated
OnLoad
OnItemCommand
OnItemDeleting
OnItemDeleted
OnItemCreated
OnDataBound
OnPreRender
OnUnload
So we can see that OnItemCreated gets fired twice, and the second time it's fired is AFTER OnItemDeleted, which means that whatever change I make is overwritten, I suppose. Now how am I supposed to handle that?
Here is working solution (You may want to improve it):
<asp:FormView ID="FormView1" runat="server" DataSourceID="ObjectDataSource1"
AllowPaging="true" OnItemDeleted="FormView1_ItemDeleted" ondatabound="FormView1_DataBound" >
<ItemTemplate>
Key:
<asp:Label ID="KeyLabel" runat="server" Text='<%# Bind("Key") %>' />
<br />
Value:
<asp:Label ID="ValueLabel" runat="server" Text='<%# Bind("Value") %>' />
<br />
<asp:Button ID="DeleteButton" runat="server" CausesValidation="False" CommandName="Delete"
Text="Delete" />
<hr />
<asp:Label ID="Label1" runat="server" Text="does not work"></asp:Label>
</ItemTemplate>
</asp:FormView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="GetList"
DeleteMethod="Delete" TypeName="MyProject.Repository">
<DeleteParameters>
<asp:Parameter Name="key" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
codebehind:
public string MyProperty { get; set; }
protected void FormView1_DataBound(object sender, EventArgs e)
{
if (!string.IsNullOrEmpty(MyProperty))
{
Label l = FormView1.FindControl("Label1") as Label;
l.Text = "it works. " + MyProperty;
MyProperty = null;
}
}
protected void FormView1_ItemDeleted(object sender, FormViewDeletedEventArgs e)
{
if (e.Exception != null)
{
MyProperty = e.Exception.Message;
e.ExceptionHandled = true;
}
}
Well, one way is to add another public field to the data source object called "Error", then in MyFormViewItemDeleted change the proper value and re-bind the FormView.
As far as I can see it should work, though there might be easier/more simple way.
Here is how I did after modifying the code a bit. In the code behind, declared a Field in the Class: private string str_feedbackmsg;
try
{
cnn.Open();
SqlCommand cmd = new SqlCommand(dbcmd, cnn);
cmd.ExecuteNonQuery();
str_feedbackmsg = "Database Work Done!";
}
catch (SqlException err)
{
str_feedbackmsg = "Database Error: Please Notify the Site Administrators.";
}
finally
{
cnn.Close();
}
Then in the Databound event for the FormView:
protected void gv_main_DataBound(object sender, EventArgs e)
{
if (IsPostBack)
{
Label l = fv_main.FindControl("lbl_feedback") as Label;
l.Text = str_feedbackmsg;
}
}

Resources