Saving a comment from inside an updatepanel in a repeater - asp.net

(Asp.net 4)
I have a blog where i use a repeater to show all the blog-articles and the comments to each blog. I'm trying to change how the users can post comments to the blog. I want to put the comments under each blog in an UpdatePanel, and when they write a comment and click on a save-button, i want to refresh the comments, so their new comment will show. But I'm having difficulties achieving this.
I've added the UpdatePanel in the ItemTemplate of the Repeater, and added the Textboxes and Button for saving the comment. Each UpdatePanel is placed in a with the id of the blog. But I don't know how to create the code for saving the comment for the correct blog-id, and then to refresh that UpdatePanel.
Code:
<asp:Repeater ID="RepeaterBlog" runat="server">
<ItemTemplate>
<article>
<% if (repeaterCounter == 0)
{
Response.Write("<header class=\"firstArticleInBlog\">");
}
else
{
Response.Write("<header class=\"normalArticle\">");
}
%>
<h2><%# Eval("article_header") %> <span class="date">
<time datetime="<%# GetPubDate(Eval("article_date")) %>"><%# FormatDate(Eval("article_date")) %></time></span></h2></header>
<p><%# Eval("article_content") %><p><br />
<div class="comments">
<div class="showhidecomments">
<!--<a class="iframe-comments" data-fancybox-type="iframe" href='WriteComments.aspx?BlogId=<%# DataBinder.Eval(Container, "DataItem.id") %>'>Skriv kommentar</a> | -->
Vis/Skriv kommentarer (<%# CountComments (DataBinder.Eval(Container, "DataItem.id")) %>) | <a href="javascript:void(0);" title="i<%# Eval("id") %>" >Skjul kommentarer</a>
</div>
<section>
<article>
<div id="i<%# Eval("id") %>" style="display: none;">
<asp:UpdatePanel ID="upPanel" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="cmdSaveComment" EventName="Click" />
</Triggers>
<ContentTemplate>
<%# GetComments (DataBinder.Eval(Container, "DataItem.id")) %>
<asp:TextBox ID="txtName" runat="server" />
<asp:TextBox ID="txtComment" runat="server" TextMode="MultiLine" />
<asp:Button ID="cmdSaveComment" runat="server" OnClick="cmdSaveComment_Click" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
</article>
</section>
</div>
<% repeaterCounter++; %>
</article>
</ItemTemplate>
</asp:Repeater>
And in the code-behind:
protected void cmdSaveComment_Click(object sender, EventArgs e)
{
//simplified code:
string name = txtName.Text;
string comment = txtComment.Text;
int blogId = (int)(Eval("DataItem.id"));
dataHandler.NewComment(name, comment, blogId);
}
Am i at least close to something here, or am i completely on the wrong track?

You need to use the ItemCommand property for the repeater and the CommandName property for your button.
First declare the event name for the repeater and the button's command name in your aspx. Note the CommandName replaces the OnClick for your button. Also you give the button a command argument, this being the ID for the article record that the comment is for.
<asp:Repeater ID="RepeaterBlog" runat="server" OnItemCommand="RepeaterBlog_ItemCommand">
<asp:Button ID="cmdSaveComment" runat="server" CommandName="SaveComment" CommandArgument='<%# Eval("id")%>' />
Now add this in the code behind
void RepeaterBlog_ItemCommand(Object Sender, RepeaterCommandEventArgs e) {
if(e.CommandName == "SaveComment") {
string name = ((TextBox)e.Item.FindControl("txtName")).Text;
string comment = ((TextBox)e.Item.FindControl("txtComment")).Text;
dataHandler.NewComment(name, comment, e.CommandArgument);
}
}
That should get you started

Related

Connecting Session from a repeater's item to another page doesn't work

I want to take the text in the text box from the particular item in the repeater that was clicked, and use it on the page ViewRecipe2.aspx.
Currently, when you click a button on one of the items, it returns back to the repeater's page, but the repeater does not appear, instead of moving to the page ViewRecipe2.aspx.
This is my repeater in aspx:
<asp:Repeater ID="RepeaterR" runat="server">
<ItemTemplate>
<div class="wrapper">
<table>
<div class="box">
<div class="property-card">
<div class="property-image">
<div class="property-image-title">
</div>
</div>
<div class="property-description">
<asp:Button CssClass="h5" runat="server" ID="Button1" OnClick="Button1_Click" Text=<%# Eval("recipeName")%> BackColor="Transparent" BorderColor="Transparent"/>
<p><%#Eval("avgRating") %> stars</p>
<asp:Image class="img" runat="server" src=<%#Eval("recipePic") %> />
<asp:TextBox ID="hiddenTB" runat="server" Text=<%# Eval("recipeName")%> Visible="false"></asp:TextBox>
</div>
</div>
</div>
</table>
</div>
</ItemTemplate>
</asp:Repeater>
This is the code behind on c#:
protected void Button1_Click(object sender, EventArgs e)
{
RepeaterItem item = (sender as Button).NamingContainer as RepeaterItem;
string VR = (item.FindControl("hiddenTB") as TextBox).Text;
if (VR!=null)
{
Session["selectedRecipe"] = VR;
Response.Redirect("ViewRecipe2.aspx");
}
}
This is ViewRecipe2.aspx:
<asp:TextBox ID="TextBoxP" runat="server"></asp:TextBox>
And the code behind:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
string theRecipeName = (Session["selectedRecipe"]).ToString();
TextBoxP.Text = theRecipeName;
}
}
Well, text box or hidden field is "never" null.
but, you need quotes around that "text" setting of the hidden field.
<asp:TextBox ID="hiddenTB" runat="server"
Text='<%# Eval("recipeName")%>' Visible="false">
</asp:TextBox>
Also, keep in mind, that with visible=false, then the markup is NOT sent nor rendered client side. This means that client side js code can't use that text box, but server side code can just fine grab the textbox, and then the value as you have.
However, while you "should" have those single quotes?
it should still have worked.
I would for testing, remove the Visible="false", and then you can actually see + verify that the value is correct.

ASP.NET - child control in a Repeater doesn't get initialized in time

I'm facing the following problem: I have an asp repeater who has a control as ItemTemplate. In codebehind, I assign a DataSource to the repeater:
...
this.ProductList = searchResult.Entry.ToList();
EntriesList.DataSource = this.ProductList;
...
void EntriesList_ItemDataBound(object sender, ListViewItemEventArgs e)
{
var productBlock = (ProductBlock)e.Item.FindControl("productBlock"); //Here I obtain the child, then assign the values from the datasource
productBlock.ProductEntry = (Entry)e.Item.DataItem;
}
This is the aspx code of the childcontrol:
<%# Control Language="C#" CodeBehind="ProductBlock.ascx.cs" Inherits="EPiServer.Commerce.Sample.Templates.Sample.Units.CategoryDisplay.SharedModules.ProductBlock" %>
<%# Import Namespace="EPiServer.Commerce.Sample" %>
<%# Import Namespace="EPiServer.Commerce.Catalog.ContentTypes" %>
<%# Import Namespace="EPiServer.Core.Html" %>
<%# Import Namespace="EPiServer.Commerce.Catalog.ContentTypes" %>
<%# Import Namespace="Mediachase.Commerce.Catalog.Objects" %>
<%# Import Namespace="Mediachase.Commerce.Website.Helpers" %>
<%# Register Src="StarButton.ascx" TagName="StarButton" TagPrefix="catalog" %>
<%# Register Src="CommonButtons.ascx" TagName="CommonButtons" TagPrefix="catalog" %>
<li class="span3">
<div class="thumbnail thumbnail-product">
<catalog:StarButton runat="server" ID="StarButton" />
<asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl='<%# ResolveUrl(StoreHelper.GetEntryUrl(ProductEntry)) %>'>
<span class="product-img-holder">
<asp:Image runat="server" ID="Image1" AlternateText="" />
</span>
</asp:HyperLink>
<div class="product-dsc">
<asp:HyperLink ID="HyperLink3" runat="server" NavigateUrl='<%# ResolveUrl(StoreHelper.GetEntryUrl(ProductEntry)) %>' CssClass="product-name">
<span><asp:Literal ID="HeadingLiteral" runat="server" /></span>
</asp:HyperLink>
<div class="tp-additional">
<ul class="unstyled">
<li><strong>Marca:</strong>
<asp:Literal ID="BrandLiteral" runat="server" />
</li>
<li>
<strong>Principio Activo:</strong>
<asp:Literal ID="ActiveIngredientLiteral" runat="server" />
</li>
<li>
<strong>Patología:</strong>
<asp:Literal ID="PathologyLiteral" runat="server" />
</li>
<%--<li><strong>In Stock:</strong> <asp:Literal ID="InStock" runat="server"></asp:Literal></li>--%>
<li><strong>Código Nacional:</strong>
<span title="<%# ProductEntry.ID %>"><%# ProductEntry.ID %></span></li>
<%--<li><strong>Model:</strong>
<%# WebStringHelper.EncodeForWebString(GetModelNumber((EntryContentBase) Container.DataItem)) %></li>
<li><strong>List Price:</strong> <asp:Literal ID="ListPrice" runat="server" /></li>
<li><strong>Discount Pricing</strong> <asp:Literal ID="DiscountPricing" runat="server" /></li>
<li><strong>You Save:</strong> <asp:Literal ID="DiscountAmount" runat="server" /></li>--%>
</ul>
<asp:PlaceHolder runat="server" Visible="False" ID="PromotionsHolder">
<%--<strong>Promotions:</strong><br />
<asp:Literal ID="Promotions" runat="server" />--%>
</asp:PlaceHolder>
</div>
<div class="C_Product-ItemSelector">
<div class="btn-group">
<a class="btn btn-info" href="<%# ResolveUrl(StoreHelper.GetEntryUrl(ProductEntry)) %>"><i class="icon-shopping-cart icon-white"></i> Ver detalles</a>
<a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="#"><span class="caret"></span></a>
<catalog:CommonButtons runat="server" ID="CommonButtons" />
</div>
</div>
</div>
</div>
</li>
The code behind of this control just sets the values that should be given to the ProductEntry public property. In the debug, immediately after executing the EntriesList.DataSource = this.ProductList; line, the application raises a NullArgumentException, telling me that ProductEntry property from the child control is null.
However, if in the code behind of the child control of the repeater I do the following:
protected void Page_Init(object sender, EventArgs e)
{
ProductEntry = new Entry();
}
Everything works as ProductEntry will not be null anymore.
This solution is rather ugly to me and I don't know why it happens and what is the best way to set a value for a child control inside a repeater. Can anyone enlighten me?
Thank you
You said Repeater control. If so, EntriesList_ItemDataBound's EventArgs should be RepeaterItemEventArgs
Another problem is you need to filter ItemType inside ItemDataBound, because Header, Footer and others also fire ItemDataBound event.
protected void EntriesList_ItemDataBound(
Object Sender, RepeaterItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem) {
var productBlock = (ProductBlock)e.Item.FindControl("productBlock");
productBlock.ProductEntry = (Entry)e.Item.DataItem;
}
}
Win your approach didn't work, child objects were still being created before and inited before I could assign them their values.
Hopefully, I've found the solution. Using the OnItemCreated event instead of the OnItemDatabound event solved my problem, as it was called when the child item was created, but before the Page_Init event of the child was called.
Thank you

get info from one page and show it on other page

i m working on shopping cart site
i want to show complete information of a product contained in a div section. on an other page. i have may div that contained information.
goal is to get the info on a new page when user clicks some product's image.
Error:
Control 'MainContent_ImageButton1' of type 'ImageButton' must be placed inside a form tag with runat=server.
HTML:
<div id="physics" runat="server">
<h3>High School Physics</h3>
<%-- <img src="images/Book.jpg" /> --%>
<asp:ImageButton ID="ImageButton1"
src="images/Book.jpg" runat="server" onclick="ImageButton1_Click" />
<p> Book Description Goes Here
<br />
<asp:Label ID="Label1" runat="server" Text="Label">PKR 770/-</asp:Label>
<br />
<asp:TextBox ID="TextBox1" Text="1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Add" />
</p>
</div>
Code :
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
StringWriter sw = new StringWriter();
HtmlTextWriter w = new HtmlTextWriter(sw);
physics.RenderControl(w);
Session["mySessionVar"] = sw.GetStringBuilder().ToString();
Response.Redirect("ShowLarge.aspx", true);
}
HTML: where i want to show this info
<div id="ShowInLargeView" runat="server">
</div>
Code:
protected void Page_Load(object sender, EventArgs e)
{
ShowInLargeView.InnerHtml = (String)Session["mySessionVar"];
}
i want to show the complete info of Div in an other page. i m getting an error. this scenario is about shopping cart
i need help
please help.
The error you are getting is related to the fact that you are trying to add an event handler
protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
In order to add an event handler to an element on your page it will need to be encapsulated in a 'form' with the runat="server" attribute. this will result in the click event of the ImageButton ending up in your code-behind.
so your aspx would become something like :
<form runat="server">
<div id="physics" runat="server">
<h3>High School Physics</h3>
<%-- <img src="images/Book.jpg" /> --%>
<asp:ImageButton ID="ImageButton1"
src="images/Book.jpg" runat="server" onclick="ImageButton1_Click" />
<p> Book Description Goes Here
<br />
<asp:Label ID="Label1" runat="server" Text="Label">PKR 770/-</asp:Label>
<br />
<asp:TextBox ID="TextBox1" Text="1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Add" />
</p>
</div>
</form>
In general it should suffice to encapsulate your entire page in a form tag, this way all events will be passed to your code-behind.

Shading every other row in a VB.net Listview?

I have been Googling this for about a day now, and every post I find is too old and Visual Studio doesn't recognize some pieces of code that people have posted. I have a dynamically populated Listview. I would really like every other line to be shaded for readability purposes, and just can't figure it out.
Everything I try to do messes with the Modal PopupExtender that I have inside of the Listview. It trys to shade the lines inside the PopUpBox too. This is one of the Listviews that I would like shaded.
<!-- Descriptions -->
<asp:TabPanel ID="tab2" runat="server" HeaderText="Descriptions">
<HeaderTemplate>Descriptions</HeaderTemplate>
<ContentTemplate>
<ul class="info">
<asp:ListView ID="lvDescriptions" runat="server" DataSourceID="dsMarketingDescriptions" DataKeyNames="MarketingID">
<ItemTemplate>
<li>
<asp:LinkButton ID="ViewDescriptionButton" runat="server"><%#Eval("MarketingTitle")%></asp:LinkButton>
<asp:Panel ID="ViewDescriptionPanel" runat="server" CssClass="DescModalPopup"> <div class="PopupHeader" id="PopupHeader">View Description
<asp:ImageButton ID="CancelDescriptionButton" runat="server" ImageUrl="../../images/exit.png" AlternateText="" Style="float:right;"/>
</div>
<asp:Label ID="Description" runat="server" style="padding:5px;"><%# Eval("MarketingData") %></asp:Label>
</asp:Panel>
<asp:ModalPopupExtender ID="ViewDescriptionModal" runat="server" BackgroundCssClass="modalBackground" DropShadow="false" DynamicServicePath="" Enabled="true" PopupControlID="ViewDescriptionPanel" TargetControlID="ViewDescriptionButton" CancelControlID="CancelDescriptionButton"></asp:ModalPopupExtender>
</li>
</ItemTemplate>
</asp:ListView>
</ul>
</ContentTemplate>
</asp:TabPanel>
Try using the AlternatingItemTemplate to specify a different background color for alternating items.
Are you trying to do something like this with the ModalPopupExtender?:
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
Panel pnl = e.Item.FindControl("Panel1") as Panel;
if (pnl != null)
{
pnl.BackColor = ListView1.Items.IndexOf(e.Item) % 2 == 1 ? Color.PeachPuff : Color.White;
}
}

How to bind a nested control from main page code behind

I have the following structure in place and need to rebind the lower control (DropDownList)
from the code behind of the MainPage.
x MainPage1 x---- Panel1 (modal popup)
x--------- UpdatePanel (upMailOrStatusAction, on Panel1)
x-------------- RadioButtonList (rblActionLevel, on UpdatePanel)
x-------------- SubForm1 (on Panel1)
x------------------- CustomControl1 (on Subform1)
x------------------------ DropDownList (on CustomControl1)
What would be the correct way to accomplish this?
I added a public method "BindMailActionLookup()" to the control, but how do I call it from the main page? I get "does not exist in the current context"?
Here is the markup of the subform:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="MailAddSubform.ascx.cs"
Inherits="Company.Solutions.Web.Controls.MailAddSubform" %>
<%# Register TagPrefix="st" TagName="MailActionLookup" Src="~/Controls/StMailActionLookup.ascx" %>
<div class="NinetyNinePercentWide">
<div class="NinetyNinePercentWide EightPixelBottomMargin">
<div class="RowHeader" style="padding-top: 20px;">
<span class="labelfield" >Action:</span>
</div>
<div>
<st:MailActionLookup ID="mailActionLookup" runat="server" />
</div>
</div>
<div class="NinetyNinePercentWide EightPixelBottomMargin" >
<br class="NinetyNinePercentWide" Text="&nbsp" />
<div class="RowHeader" >
<span class="labelfield" >Message:</span>
</div>
<div class="TwelvePixelLeftPad" >
<asp:TextBox ID="txtMailActionMessage" runat="server" MaxLength="40" />
</div>
</div>
</div>
Here is the markup for the custom control:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="StMailActionLookup.ascx.cs" Inherits="Company.Solutions.Web.Controls.StMailActionLookup" %>
<div id="mainControlContainer" style="width:99%; padding:8px;">
<div id="comboContainer" style="float:left; padding-top:12px;padding-left:5px; padding- right:5px; padding-bottom:3px;">
<asp:UpdatePanel runat="server" ID="mailActionUpdater">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="chkForms" EventName="CheckedChanged" />
<asp:AsyncPostBackTrigger ControlID="chkRequested" EventName="CheckedChanged" />
<asp:AsyncPostBackTrigger ControlID="chkOther" EventName="CheckedChanged" />
</Triggers>
<ContentTemplate>
<asp:DropDownList runat="server" ID="ddlLookup" width="240px" ondatabound="ddlLookup_DataBound1" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
<div id="filterContainer" style="text-align:left;padding-left:6px;width:275px">
<fieldset style="width:260px;">
<legend>Filters</legend>
<asp:CheckBox ID="chkForms" runat="server" Text="Forms" AutoPostBack="true" />
<asp:CheckBox ID="chkRequested" runat="server" Text="Requested Info" AutoPostBack="true" />
<asp:CheckBox ID="chkOther" runat="server" Text="Other" AutoPostBack="true" />
</fieldset>
</div>
</div>
And here is part of the code behind where I added the public method:
namespace Company.Solutions.Web.Controls
{
public partial class StMailActionLookup : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
BindForm();
}
public void BindMailActionLookup()
{
BindForm();
}
protected void BindForm()
{
GetActionLevel();
IEnumerable actions = GetClaimMailActions(GetFilter());
ddlLookup.DataSource = actions;
ddlLookup.DataTextField = "CodeAndDescription";
ddlLookup.DataValueField = "ActionCd";
ddlLookup.DataBind();
}
}
}
You shouldn't be exposing the internals of CustomControl1 to a consumer, so the most correct way would be to expose a public method (maybe call it "ResetDropDowns") on your CustomControl1 that the main page could call into.
CustomControl1 knows about it's own dropdowns, so it can easily find and rebind the control when someone calls the method.
Ok, we have a solution thanks to "womp's" suggestions and one of my co-workers.
Just keep nesting the public calls in a chain:
This in the main Claim Info code behind:
// Rebind the action code drop down to restrict to base level
mailAddSubform.BindMailActionLookup();
Then this in the subform code behind:
public void BindMailActionLookup()
{
mailActionLookup.BindMailActionLookup();
}
And finally, this in the lookup control:
public void BindMailActionLookup()
{
BindForm();
}

Resources