ASP.NET Panel FindControl within DataList to change property C# - c#

I'm new to this ASP.NET stuff. In my page I have a Datalist with a FooterTemplate. In the footer I have a couple panels that will be visible depending on the QueryString. The problem I am having is trying to find these panels on Page_Load to change the Visible Property. Is there a way to find this control in the Page_Load? For example this is part of the aspx page:
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
<asp:DataList ID="dlRecords" runat="server">
<FooterTemplate>
<asp:Panel ID="pnlArticleHeader" runat="server" Visible="false" >
</asp:Panel>
</FooterTemplate>
</asp:Datalist>
</asp:Content>
Here is something in the codebehind:
protected void Page_Load(object sender, EventArgs e)
{
location = Request.QueryString["location"];
if (location == "HERE")
{
Panel pnlAH = *Need to find control here*;
pnlAH.Visible=true;
}
}
Like I said I am new at this. Everything I have found doesn't seem to work so I decided to post a specific question. Thanks in advance

DataList has event OnItemCreated, overriding allows select type of row:
Panel _pnlArticleHeader;
void Item_Created(Object sender, DataListItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Footer)
{
_pnlArticleHeader =(Panel)e.Item.FindControl("pnlArticleHeader");
}
}
After event invocation in the field: _pnlArticleHeader you will get desired panel. This way is safe since created only once. NOTE! same way for common DataList's row would return only last one.

Related

Retrieving ascx control value from a callback registered on master page. Control added to Repeater's PlaceHolder during OnItemCreated

This is my best attempt to simplify the code to ask the question well. Hopefully it helps.
The short: I need to get the value of a dynamically created Control whose path is loaded from the database and added to a Repeater that contains a PlaceHolder. The value needs to be retrieved from a function on the child page that is called from the master page.
The long:
I have a master page that has a lot of settings on it, and an area where a child page can add its own configuration options. Let's say the master page is as follows:
<%# Master Language="C#" MasterPageFile="~/MainTemplate.master" CodeBehind="ConfigureChoices.master.cs" Inherits="Demo.ConfigureChoices"
AutoEventWireup="true" %>
<asp:Content ID="Content1" ContentPlaceHolderID="RenderArea" runat="Server">
<asp:Panel runat="server" ID="PanelConfiguration">
<asp:TextBox ID="TextBoxForSomething" runat="Server"/>
<asp:DropDownList ID="AnotherConfigurableThing" runat="server" OnSelectedIndexChanged="DropDownConfiguration_Click" AutoPostBack="true">
<asp:ListItem Text="Option 1" Selected="True" Value="1"></asp:ListItem>
<asp:ListItem Text="Option 2" Value="2"></asp:ListItem>
<asp:ListItem Text="Option 3" Value="3"></asp:ListItem>
</asp:DropDownList>
<!--etc-->
<asp:ContentPlaceHolder ID="CustomSettings" runat="server">
</asp:ContentPlaceHolder>
<asp:Button ID="ButtonSubmit" runat="Server" Text="Submit" OnClick="ButtonSubmit_Click" />
</asp:Panel>
</asp:Content>
In codebehind, I need to persist the settings to the database, including custom settings from the user page. The child pages need some of the data created from the master page in order to persist its data. To accomplish this, I have an event that gets populated on child page load and called prior to redirect. It looks like this:
public delegate void BeforeSubmitEventHandler(int configInfoID);
public event BeforeSubmitEventHandler BeforeSubmit;
protected void ButtonSubmit_Click(object sender, EventArgs e)
{
ConfigInfo config = new ConfigInfo;
config.EnteredText = TextBoxForSomething.Text;
config.SelectedValue = AnotherConfigurableThing.SelectedValue;
int configID = AddToDatabase(config);
if (BeforeSubmit != null)
BeforeSubmit(configID);
Response.Redirect("RedirectURL.aspx");
}
The custom section of the user page has a Repeater, a DropDownList, and an "Add" Button. The Repeater has the name of the option, a short description, a delete image, and a PlaceHolder for loading custom controls from the database. More on that after the code:
<%# Page Title="" Language="C#" MasterPageFile="~/ConfigureChoices.master" ValidateRequest="false"
AutoEventWireup="true" Inherits="Demo.CustomChoicePage1" Codebehind="CustomChoicePage1.aspx.cs"
MaintainScrollPositionOnPostback="true" %>
<asp:Content ID="MyContent" ContentPlaceHolderID="CustomSettings" runat="server">
<asp:Repeater ID="RepeaterSelectedOptions" OnItemCreated="OnOptionAdded" runat="server">
<HeaderTemplate>
<table id="SelectedOptionsTable">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<%# Server.HtmlEncode(Eval("Name").ToString()) %>
</td>
<td>
<%# Server.HtmlEncode(Eval("Description").ToString()) %>
</td>
<td>
<asp:ImageButton ImageUrl="delete.png" ID="ImgDeleteOption" runat="server" OnCommand="DeleteOption_Click"
CommandArgument='<%# Eval("OptionID") %>' />
</td>
</tr>
<asp:PlaceHolder runat="server" ID="optionConfiguration" />
</ItemTemplate>
<FooterTemplate>
</tbody>
</table>
</FooterTemplate>
</asp:Repeater>
<br />
<asp:DropDownList ID="DropDownListAvailableOptions" runat="server" />
<asp:Button ID="ButtonAddOption" runat="server" Text="Add Option" OnCommand="AddOption_Click" />
</asp:Content>
In codebehind, the Repeater is populated the first time on Page_Load using the following code (combination of C# and pseudocode to shorten this already-long question):
protected void Page_Load(object sender, EventArgs e)
{
((ConfigureChoices)Master).BeforeSubmit += OnSubmit;
if (!Page.IsPostBack)
{
RefreshOptions();
}
}
protected void RefreshOptions()
{
List<Option> fullList = GetOptionsFromDB();
List<Option> availableList = new List<Option>();
List<Option> selectedList = new List<Option>();
List<int> selectedOptions = GetSelectedOptions();
// Logic here to set the available/selected Lists
DropDownListAvailableOptions.DataSource = availableList;
DropDownListAvailableOptions.DataBind();
RepeaterSelectedOptions.DataSource = selectedList;
RepeaterSelectedOptions.DataBind();
}
public List<short> GetSelectedOptions()
{
List<int> selectedOptions = this.ViewState["SelectedOptions"];
if (selectedOptions == null)
{
selectedOptions = new List<int>();
foreach (Option option in GetOptionsFromDB())
{
selectedOptions.Add(option.OptionID);
}
}
return selectedOptions;
}
If the add or remove buttons are clicked, the following methods are used:
public void AddOption_Click(object sender, CommandEventArgs e)
{
List<int> selectedOptions = GetSelectedOptions();
selectedOptions.Add(Convert.ToInt32(DropDownListAvailableOptions.SelectedValue));
this.ViewState["SelectedOptions"] = selectedTests;
RefreshOptions();
}
public void DeleteOption_Click(object sender, CommandEventArgs e)
{
List<int> selectedOptions = GetSelectedOptions();
selectedOptions.Remove(Convert.ToInt32(e.CommandArgument));
this.ViewState["SelectedOptions"] = selectedOptions;
RefreshOptions();
}
Finally, the meat of where I think the issue might be, and some explanation of what I've tried. When an option is added to the control, a different table is queried to see if there's an additional ascx that must be loaded into the placeholder. This happens in the method pointed to by OnItemCreated in the Repeater:
protected void OnOptionAdded(Object sender, RepeaterItemEventArgs e)
{
if (e.Item == null || e.Item.DataItem == null)
return;
short optionID = ((Option)e.Item.DataItem).OptionID;
OptionControl optionControl = GetControlForOptionFromDB(optionID);
if (optionControl == null)
return;
CustomOptionControl control = (CustomOptionControl)this.LoadControl(optionControl.Path);
control.ID = "CustomControl" + optionID.ToString();
TableRow tableRow = new TableRow();
tableRow.ID = "CustomControlTR" + optionID.ToString();
tableRow.CssClass = "TestConfiguration";
TableCell tableCell = new TableCell();
tableCell.ID = "CustomControlTC" + optionID.ToString();
tableCell.ColumnSpan = 3;
e.Item.FindControl("optionConfiguration").Controls.Add(tableRow);
tableRow.Cells.Add(tableCell);
tableCell.Controls.Add(control);
}
So all of the above "works" in that I see the control on the page, the lists work correctly, and stuff like that. When I click the "Submit" button, I see the configuration (for the sake of this example, let's just say it's a single checkbox) in the Request form variable. However, setting a breakpoint in my callback method on the child page, the CustomOptionControl does not appear to be in the RepeaterSelectedOptions. Only the Option is present.
I have tried at least the following, and more (but I honestly can't recall every step I've tried):
adding a call to RefreshOptions to an overridden LoadViewState
after the call to load the base
doing my initial Repeater binding
in Page_Init instead of Page_Load
different orders of adding the table row, cell, and custom controls to each other and the main
page
How should I be structuring this page and its necessary databinding events so that I can make something like the commented lines in the following code work? When I break at the start of the method and look through the RepeaterOptions.Controls, the CustomOptionControls are gone.
protected void OnSubmit(int configID)
{
//List<CustomOptionControl> optionsToInsert = find CustomOptionControls in RepeaterOptions (probably an iterative search through the Controls);
//foreach (CustomOptionControl control in optionsToInsert)
//{
// control.AddOptionToDatabase(configID);
//}
}
I'm not sure what changed, maybe it was taking the break to rubber duck debug using all of the above. I've gone back and tried tweaking some of the things I had before (order of insertion, which call to use, etc) to see if they make a difference, but either way, the Control is now being persisted in the ViewState properly with the above code. It is available on postback from the master page call so long as the following is added (bullet #1 of what I tried before):
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
RefreshOptions();
}
Earlier, savedState was only showing the List<int> added to it to maintain selected options. At some point in tweaking and debugging, I saw that the controls I created were now in the viewstate, and adding a RefreshOptions call worked. This means on postback for add/remove there are two calls to RefreshOptions, but I can either work around that or ignore it, since behavior is still correct. Thanks for looking!

Unable to retrieve DDL SelectedValue bound in ASPX after Page Load

I have the following markup / code block in the ASPX file.
The binding of the ddl is triggered after Page_Load event which is in the code behind file.
This results me not able to get the selected value of the dropdownlist if I were to use such flow.
However for some purpose I require it to work this way.
Any idea how I could get the dropdownlist selected value when a post back is being triggered (click of the button)?
Page URL: page.aspx?para1=0&para2=value
ASPX PAGE
<%
if (Convert.ToInt32(Request.QueryString["para1"]) == 0)
{
ddl.DataValueField = "value";
ddl.DataTextField = "text";
ddl.DataSource = ds; //ds is valid, exact code not shown
ddl.DataBind();
} else {
//write in this area
Response.Write("Not 0");
}
%>
<form runat="server" id="user_form" class="form-horizontal">
<asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server">
</asp:ToolkitScriptManager>
<asp:UpdatePanel ID="updPanel" runat="server">
<ContentTemplate>
<asp:DropDownList runat="server" ID="ddl">
</asp:DropDownList>
<%-- this button will call btnSave_Click to get the ddl's value--%>
<asp:Button runat="server" ID="btn" Text="Button" OnClick="btn_Click" />
</ContentTemplate>
</asp:UpdatePanel>
</form>
CODE BEHIND
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//do my stuff
}
}
protected void btn_Click(object sender, EventArgs e)
{
int intValue = Convert.ToInt32(ddl.SelectedValue);
//do my stuff
}
The ASPX Page code block will run after Page_Load / page's lifecycle, then will determine what to do base on the url parameters.
Thanks in advance!
You could always throw in a hidden object and use jquery to copy the value to the hidden value based on a certain action without a postback and would do it client side like it sounds like you want it to do

How to add web user controls to repeater

Scenario:
UsrControl: custom user control, which contains a textbox and a button, rederend horizontally (in one line).
UsrControlContainer: custom user control, which should be able to display multiple UsrControl objects (each object in seperate line, so the Seperator template will probably be <br />. This control also contains a button, which adds new UsrControl to the collection.
My code:
<asp:Button ID="Button1" runat="server" Text="Button" onclick="Button1_Click"/>
<asp:Repeater ID="rptExample" runat="server">
<ItemTemplate>
</ItemTemplate>
<SeparatorTemplate><br /></SeparatorTemplate>
</asp:Repeater>
And:
protected void Button1_Click(object sender, EventArgs e)
{
rptExample.DataSource = new List<UsrControl> {new UsrControl(), new UsrControl()};
rptExample.DataBind();
}
Simple question - what should I put in ItemTemplate to make this work?
Edit - I also want to pass some parameters to UsrControl before rendering it.
<asp:Repeater ID="rptExample" runat="server">
<ItemTemplate>
<uc:UsrControl runat="server" />
</ItemTemplate>
<SeparatorTemplate><br /></SeparatorTemplate>
</asp:Repeater>
protected void Button1_Click(object sender, EventArgs e)
{
rptExample.DataSource = Enumerable.Range(0, 2);
rptExample.DataBind();
}
Following your question in answer. You can catch every binding object in ItemDataBound event. So for example, as i used, set whole object as user control property.
protected void PersonesRepeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
PersonLine line = (PersonLine)e.Item.FindControl("Person1");
line.Person = e.Item.DataItem as Osoba;
}
}
Ofcourse, you have to add the event handler to your repeater:
<asp:Repeater runat="server" ID="PersonesRepeater" OnItemDataBound="PersonesRepeater_ItemDataBound"><ItemTemplate>
<my:Person ID="Person1" runat="server" />
</ItemTemplate>
</asp:Repeater>

Getting control value when switching a view as part of a multiview

I have the following code in my aspx page:
<asp:Button id="display_button" runat="server" Text="Display" OnClick="Button1_Click" />
<asp:Button id="edit_button" runat="server" Text="Edit" OnClick="Button2_Click" />
<asp:Button id="save_button" runat="server" Text="Save" OnClick="Button3_Click" Visible="false" />
<asp:MultiView id="MultiView1" runat="server" ActiveViewIndex="0">
<asp:View id="View1" runat="server">
<asp:FormView id="view_program" runat="server">
<ItemTemplate>
<%# Eval("status").ToString().Trim() %>
</ItemTemplate>
</asp:FormView>
</asp:View>
<asp:View id="View2" runat="server">
<asp:FormView id="edit_program" runat="server">
<ItemTemplate>
<asp:DropDownList id="p_status" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:FormView>
</asp:View>
</asp:MultiView>
and the following functions attached to the buttons in the code-behind page:
protected void Button1_Click(object sender, EventArgs e)
{
MultiView1.SetActiveView(View1);
save_button.Visible = false;
}
protected void Button2_Click(object sender, EventArgs e)
{
MultiView1.SetActiveView(View2);
save_button.Visible = true;
}
protected void Button3_Click(object sender, EventArgs e)
{
DropDownList p_status = edit_program.FindControl("p_status") as DropDownList;
var status = p_status.SelectedValue;
Label1.Text = status;
//save_button.Visible = false;
//MultiView1.SetActiveView(View1);
}
The idea being, that there are two views, the first displays the information, if the user wants to edit the information, they click button 2 which changes the view to the edit mode, which has the controls (drop downs, text fields, etc). It also makes the 'save' button appear.
What I am trying to make happen is, when the save button is clicked, it will grab all of the values from the various fields, update the object and then update the database. Then it would flip back to view1 with the updated info.
Problem is, as you can see in void Button3_Click, I try grab the values from the control, p_status, but it only gets the original value. example, the menu has three values, 'Green', 'Yellow', and 'Red'. Green is the default value and is selected when view2 is displayed. However, if I select Yellow or Red, and click save, rather than the label being updated to display one of those two values, it always displays Green.
Any ideas?
edit: page load function per request below
protected void Page_Load(object sender, EventArgs e)
{
try
{
Person myPerson = new Person(userid);
TestProgram myProgram = new TestProgram(id);
List<TestProgram> program = new List<TestProgram> { myProgram };
view_program.DataSource = program;
view_program.DataBind();
edit_program.DataSource = program;
edit_program.DataBind();
DropDownList p_status = edit_program.FindControl("p_status") as DropDownList;
p_status.Items.Add(new ListItem("Green", "Green"));
p_status.Items.Add(new ListItem("Yellow", "Yellow"));
p_status.Items.Add(new ListItem("Red", "Red"));
//myProgram.Status = "Red";
p_status.SelectedValue = myProgram.Status;
}
catch (Exception ex)
{
Response.Write(ex);
Label1.Text = ex.ToString();
}
}
Whoops...missed a little someting.. my
bad
when asp.net is not behaving as expected this is your best friend: MSDN: ASP.NET PAGE LIFECYLE
Upon Further Review...
there are a couple of problems here. your drop down list control with an id of "p_status" is contained inside a multiview (I forgot about what that meant...) you need to move the code to populate p_status into pre-render after checking to see if Multiveiw1.ActiveView = View2. Since it will always be a post back you need to bind values late in the page cycle

How to re-bind ListView on OnClick event of a button?

this seemed simple at first but I can't get it to work.
I have the following scenario:
<asp:ListView ID="CommentsListView" runat="server">
<LayoutTemplate>
<asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</LayoutTemplate>
<ItemTemplate>
<UC:Comment runat="server" CommentItem="<%# CurrentComment %>" />
<br />
</ItemTemplate>
</asp:ListView>
<asp:TextBox ID="NewComment" runat="server" />
<asp:ImageButton ImageUrl="/images/ball.png" runat="server"
OnClick="SubmitComment" />
Code:
protected void Page_Load(object sender, EventArgs e)
{
RenderListView();
}
protected void RenderListView()
{
CommentsListView.DataSource = //Get the data source objects
CommentsListView.DataBind();
}
protected CommentObject CurrentComment
{
get { return (CommentObject)Page.GetDataItem(); }
}
protected void SubmitComment(object sender, ImageClickEventArgs e)
{
//code to submit comment
RenderListView();
}
basically, when I submit a comment, I want to see it in the ListView, but I don't. "MyControl" gets a null comment in the post-back, for all of the items (not just the new one).
Only after I refresh the page, I can see the new comment that I'v submitted. I can't however refresh the page every submit because this code is inside an UpdatePanel (the issue occurs without the UpdatePanel as well).
Any idea how to solve this?
I can't find any specifics on this, but I have a hunch the user control in your ItemTemplate is causing the issue. Can you remove it and see if it works?
I notice that you are calling RenderListView in both SubmitComment and PageLoad which I believe will cause it to fire twice when the button is clicked (with PageLoad firing first). It looks like the code you posted is simplified. Is it possible that there is something happening in the PageLoad which is sabotaging your SubmitComment steps?
I finally solved it, if anyone else may encounter this -
The solution was to avoid "<%#" and instead use the ItemDataBound event:
<asp:ListView ID="Comments" runat="server"
OnItemDataBound="CommentsItemDataBound">
and the method itself:
protected void CommentsItemDataBound(object sender, ListViewItemEventArgs e)
{
var commentItem = (Comment)(((ListViewDataItem)e.Item).DataItem);
var commentControl = (Comment)e.Item.FindControl("CommentControl");
commentControl.CommentItem = commentItem;
}
This way, the binding of each control works as expected.

Categories