How can I reference a repeater inside a usercontrol inside a webpart - c#

Noobie, question, I dont remember !
I created a visual webpart, which creates a user control, I added a repeater in htnml view, and now I need to bind it to data, however I cant seem to find the repeater control in the codebehind.
<table id="engagementletterReport" class="display" border="0">
<thead>
<tr>
<th>JobCode</th>
<th>JobName</th>
</tr>
</thead>
<tbody>
<asp:Repeater runat="server" ID="repeater">
<ItemTemplate>
<tr>
<td>
<%# DataBinder.Eval(Container.DataItem, "JobCode") %>
</td>
<td>
<%# DataBinder.Eval(Container.DataItem, "JobName") %>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
And my webpart
public class EngagementLetterWebPart : WebPart
{
// Visual Studio might automatically update this path when you change the Visual Web Part project item.
private const string _ascxPath = #"~/_CONTROLTEMPLATES/15/xx.SP.xx.WebParts.WebParts/EngagementLetterWebPart/EngagementLetterWebPartUserControl.ascx";
protected override void CreateChildControls()
{
Control control = Page.LoadControl(_ascxPath);
Controls.Add(control);
}
protected override void OnLoad(EventArgs e)
{
BindData();
}
private void BindData()
{
//here, how??
repeater.DataSource = JobContext.GetEngagementLetterReport(SPContext.Current.Site, true, 500, 1);
repeater.DataBind();
}
}

You can bind the repeater using following steps
1.Declare a public variable
Control innerControl;
2.Change the createchildcontrols function as below
protected override void CreateChildControls()
{
innerControl = Page.LoadControl(_ascxPath);
Controls.Add(innerControl);
}
3.Change the BindData function as below
private void BindData()
{
if (innerControl != null)
{
//here, how??
Repeater repeater = innerControl.FindControl("repeater") as Repeater;
if (repeater != null)
{
repeater.DataSource = JobContext.GetEngagementLetterReport(SPContext.Current.Site, true, 500, 1);
repeater.DataBind();
}
}
}

Related

Strange conflict between get postback control and RegisterStartupScript

Please consider this scenario:
I have a simple page and I want to log all controls causing postback. I create this simple page. It contains a grid to show some URLs and when user click on an icon a new tab should open:
<form id="form1" runat="server">
<div>
<table style="width: 100%;">
<tr>
<td style="background-color: #b7ffbb; text-align: center;" colspan="2">
<asp:Button ID="Button3" runat="server" Text="Click Me First" Height="55px" OnClick="Button3_Click" />
</td>
</tr>
<tr>
<td style="background-color: #f1d8fe; text-align: center;" colspan="2">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false" BackColor="White" OnRowCommand="GridView1_RowCommand">
<Columns>
<asp:BoundField DataField="SiteAddress" HeaderText="Address" />
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="ImageButton1" ImageUrl="~/download.png" runat="server" CommandArgument='<%# Eval("SiteAddress") %>' CommandName="GoTo" Height="32px" Width="32px" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</td>
</tr>
</table>
</div>
</form>
and code behind:
public partial class WebForm2 : Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button3_Click(object sender, EventArgs e)
{
List<Address> Addresses = new List<Address>()
{
new Address(){ SiteAddress = "https://google.com" },
new Address(){ SiteAddress = "https://yahoo.com" },
new Address(){ SiteAddress = "https://stackoverflow.com" },
new Address(){ SiteAddress = "https://learn.microsoft.com/}" }
};
GridView1.DataSource = Addresses;
GridView1.DataBind();
}
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
ScriptManager.RegisterStartupScript(this, this.GetType(), "MyScript", "window.open('" + e.CommandArgument.ToString() + "', '_blank')", true);
}
}
class Address
{
public string SiteAddress { get; set; }
}
every thing is fine till here. Now I create a base class for all of my pages and add below codes for finding postback control:
public class MyPageBaseClass : Page
{
protected override void OnInit(EventArgs e)
{
if (!IsPostBack)
{
}
else
{
var ControlId = GetPostBackControlName(); <------
//Log ControlId
}
base.OnInit(e);
}
private string GetPostBackControlName()
{
Control control = null;
string ctrlname = Page.Request.Params["__EVENTTARGET"];
if (ctrlname != null && ctrlname != String.Empty)
{
control = Page.FindControl(ctrlname);
}
else
{
foreach (string ctl in Page.Request.Form)
{
Control c;
if (ctl.EndsWith(".x") || ctl.EndsWith(".y"))
{
string ctrlStr = ctl.Substring(0, ctl.Length - 2);
c = Page.FindControl(ctrlStr);
}
else
{
c = Page.FindControl(ctl);
}
if (c is System.Web.UI.WebControls.Button ||
c is System.Web.UI.WebControls.ImageButton)
{
control = c;
break;
}
}
}
if (control != null)
return control.ID;
else
return string.Empty;
}
}
and change this line:
public partial class WebForm2 : MyPageBaseClass
Now when I click on icons grid view disappears...(STRANGE...) and nothing happened. When I comment specified line then every thing will be fine...(STRANGE...).
In GetPostBackControlName nothings changed to Request but I don't know why this happened. I checked and I see if I haven't RegisterStartupScript in click event every thing is fine. Please help we to solve this problem.
Thanks
when I click on icons grid view disappears...
ASP.Net page class object instances only live long enough to serve one HTTP request, and each HTTP request rebuilds the entire page by default.
Every time you do a postback, you have a new HTTP request and therefore a new page class object instance and a completely new HTML DOM in the browser. Any work you've done for a previous instance of the page class — such as bind a list of addresses to a grid — no longer exists.
You could fix this by also rebuilding your grid code on each postback, but what I'd really do is skip the whole "RegisterStartupScript" mess and instead make the grid links open the window directly, without a postback at all.
The problem is related to OnInit event. I replaced it with OnPreLoad and every things is fine now.
For search engines: OnInit event has conflict with RegisterStartupScript

ASP.NET - ImageButton within a Repeater refuses to raise a click event

No matter what combination I try, the button (ibtnDeleteDiaryEntry) simply will not raise an event although it does seem to do postback as it should. ViewState is turned on by default, read elsewhere that it is sometimes problematic. Also, I've used the Repeater's OnItemCommand property as required. Any kind of help is appreciated.
EDIT: It seems that the problem is somehow connected to the jQuery UI's Accordion Widget. The repeater is located within a div that is used to initialize the accordion. If I remove the div tags surrounding the repeater, the OnItemCommand event gets called. Very weird.
Markup:
<asp:Repeater ID="repAccordion" OnItemCommand="repAccordion_OnItemCommand" runat="server">
<ItemTemplate>
<h3> <%# "Date: " + Eval("date", "{0:d}") %>
<span class="deleteButtonContainer">
<asp:ImageButton ID="ibtnDeleteDiaryEntry" CommandArgument='<%# Eval("diary_entry_id") %>' CommandName="Delete" AlternateText="ibtnDeleteDiaryEntry" ImageUrl="images/remove_item.png" runat="server" />
</span>
</h3>
<div>
<table>
<tr>
<td>
<asp:Label ID="lblText" runat="server" ForeColor="#AA0114" Text="Text:"></asp:Label>
</td>
</tr>
<tr>
<td>
<%# Eval("text") %>
</td>
</tr>
</table>
</div>
</ItemTemplate>
</asp:Repeater>
Code-behind:
protected void Page_Load(object sender, EventArgs e)
{
_db = new PersonalOrganizerDBEntities();
_diary_entryService = new Diary_EntryService();
_userService = new UserService();
if (!IsPostBack)
{
LoadItems();
}
}
public void LoadItems()
{
long currentUserId = (long) Session["userId"];
User currentUser = _userService.GetById(currentUserId);
Diary_Entry[] diaryEntriesArray =
_diary_entryService.GetAll().Where(current => current.diary_id == currentUser.user_id).ToArray();
if (diaryEntriesArray.Length == 0)
{
noItems.Text = "You currently have no diary entries.";
noItems.Visible = true;
}
else
{
noItems.Visible = false;
}
repAccordion.DataSource = diaryEntriesArray;
repAccordion.DataBind();
}
protected void repAccordion_OnItemCommand(object sender, RepeaterCommandEventArgs e)
{
Response.Write("test");
}
If it doesn't work I would recommend removing OnItemCommand from repeater and adding OnClick event for ImageButton instead. In OnClick event in code behind you can cast 'sender' to ImageButton and read CommandArgument value to get diary_entry_id.

How to access values from dynamically added user control?

I want to get values from dynamically added user control
I'm trying but count comes as 0 so condition failed
Code:
private const string VIEWSTATEKEY = "ContactCount";
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
//Set the number of default controls
ViewState[VIEWSTATEKEY] = ViewState[VIEWSTATEKEY] == null ? 1 : ViewState[VIEWSTATEKEY];
//Load the contact control based on Vewstate key
LoadContactControls();
}
}
private void LoadContactControls()
{
for (int i = 0; i < int.Parse(ViewState[VIEWSTATEKEY].ToString()); i++)
{
rpt1.Controls.Add(LoadControl("AddVisaControl.ascx"));
}
}
protected void addnewtext_Click(object sender, EventArgs e)
{
ViewState[VIEWSTATEKEY] = int.Parse(ViewState[VIEWSTATEKEY].ToString()) + 1;
LoadContactControls();
}
EDIT
Here is the problem count takes as 0 so condition failed loop comes out
private void saveData()
{
foreach (var control in rpt1.Controls)
{
var usercontrol = control as VisaUserControl;
string visaNumber = usercontrol.TextVisaNumber;
string countryName = usercontrol.VisaCountry;
}
}
}
protected void Save_Click(object sender, EventArgs e)
{
saveData();
}
.ascx.cs
public string TextVisaNumber
{
get { return txtUser.Text; }
set { txtUser.Text = value; }
}
public string VisaCountry
{
get { return dropCountry.SelectedValue; }
set { dropCountry.SelectedValue = value; }
}
.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="AddVisaControl.ascx.cs" EnableViewState="false" Inherits="Pyramid.AddVisaControl" %>
<%# Register assembly="BasicFrame.WebControls.BasicDatePicker" namespace="BasicFrame.WebControls" tagprefix="BDP" %>
<div id="divreg" runat="server">
<table id="tbl" runat="server">
<tr>
<td>
<asp:Label ID="lbl2" runat="server"></asp:Label>
</td>
</tr>
<tr>
<td> Visa Number:</td>
<td><asp:TextBox ID="txtUser" Width="160px" runat="server"/></td>
<td> Country Name:</td>
<td><asp:DropDownList ID="dropCountry" Width="165px" runat="server"></asp:DropDownList></td>
</tr>
<tr>
<td> Type of Visa:</td>
<td><asp:DropDownList ID="dropVisa" Width="165px" runat="server"></asp:DropDownList></td>
<td> Type of Entry:</td>
<td><asp:DropDownList ID="dropEntry" Width="165px" runat="server"></asp:DropDownList></td>
</tr>
<tr>
<td> Expiry Date</td>
<td><BDP:BasicDatePicker ID="basicdate" runat="server"></BDP:BasicDatePicker></td>
<td>
<asp:Button ID="btnRemove" Text="Remove" runat="server" OnClick="btnRemove_Click" />
</td>
</tr>
</table>
</div>
Any ideas? Thanks in advance
You need to create public property in your user control.
And access that property through the id of the user control.
See this and This question.
Always assign id to the controls you are adding its a good practice.
Control ctrl = Page.LoadControl("~/UserControls/ReportControl.ascx");
ctrl.ID = "UniqueID";
Also since you are adding controls dynamically you need to manage view state of the same, or add third party controls who do this part for you.

catching SelectedIndexChanged of a dropdown list inside a repeater

I am trying to catch the SelectedIndexChanged of a DropDownList inside a Repeater. I have searched the internet but could not find a specific answer any help would be great. This is my code.
page.aspx
<asp:Repeater id="CategoryMyC" OnItemCommand="SomeEvent_ItemCommand" runat="server">
<HeaderTemplate>
<table><tr>
</HeaderTemplate>
<ItemTemplate>
<td>
<table width="100%">
<tr>
<th>Edit Carousel Item</th>
</tr>
<tr>
<td>Choose a product:</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="ddlMcProducts"
DataTextField="Name"
onselectedindexchanged="MyListIndexChanged"
AutoPostBack="true"
DataSource='<%# ProductsManager.GetMerchantProductRepeater(Convert.ToInt32(Eval("MID"))) %>'
runat="server">
</asp:DropDownList>
</td>
</tr>
</table>
</td>
</ItemTemplate>
<FooterTemplate>
</tr>
</table>
</FooterTemplate>
</asp:Repeater>
page.aspx.cs
In the Page_Load:
List<CarouselProducts> CP = CarouselProductsManager.GetCarouselItems(Convert.ToInt32(Session["Mid"]));
CategoryMyC.DataSource = CP;
CategoryMyC.ItemDataBound += new RepeaterItemEventHandler(RepeaterItemDataBound);
CategoryMyC.DataBind();
Other events:
protected void ddlMcProducts_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList d = (DropDownList)sender;
// Use d here
System.Windows.Forms.MessageBox.Show("I am changing");
}
protected virtual void PageInit(object sender, EventArgs e)
{
//get all the Carousel item of the merchant
List<CarouselProducts> CP = CarouselProductsManager.GetCarouselItems(Convert.ToInt32(Session["Mid"]));
//MerchantCategoryMyCarousel.DataSource = CP;
//MerchantCategoryMyCarousel.DataBind();
MerchantCategoryMyCarousel.DataSource = CP;
MerchantCategoryMyCarousel.ItemDataBound += new RepeaterItemEventHandler(RepeaterItemDataBound);
MerchantCategoryMyCarousel.DataBind();
}
protected virtual void RepeaterItemDataBound(object sender, RepeaterItemEventArgs e)
{
DropDownList theDropDown = sender as DropDownList;
if (e.Item.ItemType == ListItemType.EditItem)
{
DropDownList MyList = (DropDownList)e.Item.FindControl("ddlMcProducts");
if (MyList == null)
{
System.Windows.Forms.MessageBox.Show("Did not find the controle");
}
else
MyList.SelectedIndexChanged += new EventHandler(MyListIndexChanged);
}
}
protected virtual void MyListIndexChanged(object sender, EventArgs e)
{
System.Windows.Forms.MessageBox.Show("I am changing");
}
protected void SomeEvent_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
if (e.CommandSource.GetType() == typeof(DropDownList))
{
DropDownList ddlSomething = (DropDownList)e.Item.FindControl("ddlSomething");
System.Windows.Forms.MessageBox.Show("I am changing");
//Now you can access your list that fired the event
//SomeStaticClass.Update(ddlSomething.SelectedIndex);
}
}
I need to catch the SelectedIndexChanged of the populated DropDownList for each one generated.
You've got quite a mismatch of code going on here - using System.Windows.Forms in an ASP.NET application is just one of the issues. You appear to be assigning event handlers in the code-behind and in the markup (nothing necessarily bad about that, but there's seems to be no rhyme or reason to how you're doing it).
You're Repeater's ItemCommand event is bound to a method that is looking for a DropDownList that has a different ID than the one in your markup.
If you're using the System.Windows.Forms.MessageBox to debug (ala old school JavaScript and other language "debugging" methods), save yourself a world-class headache (not to mention a lot of unnecessary code cleanup when you're done with development) and step through your code in the debugger.
I'm not sure how the page will render, but I don't think you're using the HeaderTemplate and FooterTemplate quite the way they're intended.
All that said, try something like this:
Markup (ASPX page):
<asp:Repeater id="CategoryMyC" OnItemCommand="CategoryMvC_ItemCommand" OnItemDataBound="CategoryMvC_ItemDataBound" runat="server">
<HeaderTemplate>
<table>
<tr>
<th>Edit Carousel Item</th>
</tr>
</table>
</HeaderTemplate>
<ItemTemplate>
<table width="100%">
<tr>
<td>Choose a product:</td>
</tr>
<tr>
<td>
<asp:DropDownList ID="ddlMcProducts"
DataTextField="Name"
OnSelectedIndexChanged="ddlMcProducts_SelectedIndexChanged"
AutoPostBack="true"
DataSource='<%# ProductsManager.GetMerchantProductRepeater(Convert.ToInt32(Eval("MID"))) %>'
runat="server">
</asp:DropDownList>
</td>
</tr>
</table>
</ItemTemplate>
</asp:Repeater>
Code Behind (APSX.CS)
protected void Page_Load(object sender, EventArgs e)
{
List<CarouselProducts> CP = CarouselProductsManager.GetCarouselItems(Convert.ToInt32(Session["Mid"]));
CategoryMyC.DataSource = CP;
//This can be assigned in the markup
//CategoryMyC.ItemDataBound += new RepeaterItemEventHandler(RepeaterItemDataBound);
CategoryMyC.DataBind();
}
protected void ddlMcProducts_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList d = (DropDownList)sender;
// Use d here
}
protected void CategoryMyC_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
DropDownList theDropDown = sender as DropDownList;
if (e.Item.ItemType == ListItemType.EditItem)
{
DropDownList MyList = (DropDownList)e.Item.FindControl("ddlMcProducts");
// This section is not needed for what you are doing with it:
// If the control is null, handle it as an error
// There's no need to give it an event handler if it does exist, because
// you already did so in the markup
//if (MyList == null)
//{
//System.Windows.Forms.MessageBox.Show("Did not find the controle");
//}
//else
//MyList.SelectedIndexChanged += new EventHandler(MyListIndexChanged);
//}
}
}
protected void CategoryMyC_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
if (e.CommandSource.GetType() == typeof(DropDownList))
{
// Note the correct control name is being passed to FindControl
DropDownList ddlSomething = (DropDownList)e.Item.FindControl("ddlMcProducts");
//System.Windows.Forms.MessageBox.Show("I am changing");
//Now you can access your list that fired the event
//SomeStaticClass.Update(ddlMcProducts.SelectedIndex);
}
There may be more issues at hand as well - but this will hopefully streamline it enough for you to make some progress.
protected void drpOrganization_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddl = (DropDownList)sender;
RepeaterItem item = (RepeaterItem)ddl.NamingContainer;
if (item != null)
{
CheckBoxList list = (CheckBoxList)item.FindControl("chkSite");
if (list != null)
{
}
}
}

How to show/hide table row <tr> in .ascx page

I tried this, but could not get through:-
code behind
protected HtmlTableRow trComment;
protected void Page_Load(object sender, EventArgs e)
{
//Show/Hide table rows (TR)
trComment.Visible = ConfigUtil.DisplaySummaryComment;
}
.ascx page
<tr id="trComment" runat="server">
<td style="vertical-align:top; text-align:left;">
<%#ConfigUtil.FieldLabels["PIComments"]%>
:
</td>
<td>
<%= Test.Comment %>
</td>
</tr>
Your original code doesn't work, not because it's incorrect, but because you probably have more places with trComment (in which case it should error) or because your current code is inside a template of some sort (in a GridView, a Repeater). The latter is most likely, because you use a data-statement (<%#), which is commonly placed in a databound control template (but not necessarily).
One way to solve this uniformly and easily (many ways exist and it's probably best not to use literal tables anyway) is to use an asp:PlaceHolder, which does not leave HTML "traces", but can be used to toggle any block of HTML / ASP.NET code:
<!-- toggle through OnLoad (can use ID as well) -->
<asp:PlaceHolder runat="server" OnLoad="MakeVisibleOrNot">
<tr>
...
</
</asp:PlaceHolder>
in the code behind
protected void MakeVisibleOrNot(object sender, EventArgs e)
{
((Control) sender).Visible = ConfigUtil.DisplaySummaryComment;
}
<tr id="trComment" runat="server">
<td>
</td>
</tr>
Then in your Page_Load() method find your element and set visibility true or false like below
protected void Page_Load(object sender, EventArgs e)
{
trComment.Visible = false; //or trComment.Visible = true; as you wish
}
Hope this helps you
Try
trComment.Style.Add("display", "none");
This also works with no code behind
<asp:PlaceHolder runat="server" Visible ='<%# Convert.ToBoolean(Session["sess_isArtist"].ToString() == "1" || Session["sess_isBeneficiary"].ToString() == "1" ? "true": "false") %>'>
<tr>
...
</
</asp:PlaceHolder>

Categories

Resources