CollapsiblePanelExtender inside a ListView - c#

I am trying to have a collapsible panel inside of a listview item. In the item template, I have a panel, and a collapsible panel extender. In order to set the attributes TargetControlID, CollapseControlID, etc., I need the ClientIDs that are generated after databinding for each of the listview items. Does anyone know how I can set those attributes client-side?
I've tried various things along the lines of the following:
<ItemTemplate>
<asp:Panel ID="ManagingPanel" runat="server">
</asp:Panel>
<asp:CollapsiblePanelExtender runat="server" TargetControlID='<%="ManagingPanel.ClientID" %>' />
</ItemTemplate>
SOLUTION - Turns out you do not need to use the ClientID. The Extender will recognize that its target is inside the same listview item.
<asp:CollapsiblePanelExtender runat="server" TargetControlID="ManagingPanel" />

I have create a custom user control that includes the CollapsiblePanelExtender and every other think that I like to show, a complex html struct, and then I have include this control in the repeater.
The repeater pass the data that I need to render my custom control, and then the custom control render its self in every line of the repeater, and all is working fine.
something like
<asp:Repeater ID="myRepeater" runat="server">
<ItemTemplate>
<uc1:MyCustonControl ID="lPro" runat="server" data="<%#PassData%>" />
</ItemTemplate>
</asp:Repeater>

Turns out you do not need to use the ClientID. The Extender will recognize that its target is inside the same listview item.
<asp:CollapsiblePanelExtender runat="server" TargetControlID="ManagingPanel" />

Related

Change a Control in Header of an Accordion from a nested Accordion

I am using the AjaxControlToolKit.
I have an Accordion with an Image inside the Header-Template.
Inside the Content-Template there is a nested Accordion.
These two Accordions are each inside an UserControl. So the parent Accordion has an UserControl inside the Content.
If I am changing a specific control inside the nested Accordion, the nested UserControl calles a public Method of the parent UserControl which changes the source of the Image I have mentioned.
I'm doing this this way because I want to avoid a DataBind because it's very heavy loaded.
While debugging it seems to work because the new value is set to the source and will be stored to the next Postback. But the responsed site does not show the new values.
Is there a way to change the values and show it on response?
Edit - Here some striped code...
Structure:
#Site
#DocumentationPanel-UserControl (OuterAccordion)
#InnerDocumentAccordion-UserControl (InnerAccordion)
#/DocumentationPanel
#/Site
Striped Code:
<table><tr><td>
<ajaxtoolkit:accordion id="accordionGrid" runat="server" style="overflow: visible;">
<%-- Header --%>
<headertemplate>
<img id="imgUserExamState1" runat="server" title="" alt="" src="" />
</headertemplate>
<%-- Contenter --%>
<contenttemplate>
<ajaxtoolkit:accordion id="accordionGridExaminations" runat="server">
<%-- Header --%>
<headertemplate>
<img id="imgUserExamState2" runat="server" title="" alt="" src="" />
</headertemplate>
<%-- Contenter --%>
<contenttemplate>
...
</contenttemplate>
</ajaxtoolkit:accordion>
</contenttemplate>
</ajaxtoolkit:accordion>
</td></tr></table>
Now I am calling from inside the InnerDocumentAccordion the Parent, casting it to DocumentationPanel and using the public Property that links to the outer Accordion.
The InnerDocumentAccordion-Control knows the PaneIndex of the outer Accordion it is in, so I can call the wanted Pane directly and find the image (imgUserExamState1) in the header.
That looks like this:
AccordionContentPanel acp = ((DocumentationPanel)this.ParentControl).AccordionGrid.Panes[this.ParentAccordionIndex].HeaderContainer;
HtmlImage image = ((HtmlImage)(acp.FindControl("imgUserExamState")));
image.Src = "funny.png";
I can change it but there are no changes about the image in the responsed site. I tried to call a public function of DocumentationPanel, so the changes where made inside the same class the outer Accordion is in, but as expected - no success
I have tried to Rebind the outer Accordion but it says that no modification can be done while init, load, prerender etc. But it was only a try from the start.

Can a CollapsiblePanelExtender expand from code behind?

I have added a checkbox to the rows of a gridview that when clicked will expand a panel in the row. My gridview needs to use paging, so I am saving in a session variable the state of the current page before the page change. When the user clicks back to a page I am repopulating the checkboxes, but this does not expand the panels. Is there away to expand the panels from the code behind?
<asp:CheckBox runat="server" Text="Order Updated Records" ID="cbUR" Visible='<%# !DBNull.Value.Equals(Eval("AnyBox"))%>' />
<asp:CollapsiblePanelExtender ID="cInst" runat="server" TargetControlID="inst" Collapsed="true" AutoExpand="true" AutoCollapse="false" ExpandControlID="cbUR" CollapseControlID="cbUR" />
<asp:Panel ID="Inst" runat="server">
<asp:TextBox runat="server" ID="txtInst" TextMode="MultiLine" Width="200" />
</asp:panel>
I tried adding the panel, textbox and panel extender from the code, but could not get it to work. I read on a different post that the whole gridview would need to load from the code for this to work.
I would love to use something like
<asp:CollapsiblePanelExtender ID="cInst" runat="server" TargetControlID="inst" Collapsed='<%#!Convert.ToBoolean(rowItems[index].ToString()) %>' />
Would it be better not use the CollapsiblePanelExtender and find a different way to show the panels?
You could try adding a public/protected method:
public bool IsCollapsed(object rowId) {
//get row by ID here and return true if collapsed
return ....
}
that would return a value for a row that needs to be expanded or collapsed.
and use it like:
Collapsed='<%# IsCollapsed(Eval("RowId")) %>'
where RowId is a property that represents the ID of the item.

C# Issue finding controls inside of nested Accordions

I have a user control comprised of two nested accordions with a repeater inside, all of which are pulled from a database. The repeater has CheckBoxes with MutuallyExclusiveCheckBoxExtenders inside. When the page posts back I am attempting to use LINQ along with a recursive FindControl function to gather all of the CheckBoxes. The issue is that the CheckBoxes are not being located.
Basic Structure, cleaned up for brevity:
<ajaxToolkit:Accordion ID="acc1">
<ContentTemplate>
<ajaxToolkit:Accordion ID="acc2">
<ContentTemplate>
<asp:Repeater ID="r1">
<ItemTemplate>
<asp:CheckBox ID="cb1" />
<asp:CheckBox ID="cb2" />
<ajaxToolkit:MutuallyExclusiveCheckBoxExtender ID="mece1" TargetControlID="cb1" />
<ajaxToolkit:MutuallyExclusiveCheckBoxExtender ID="meceMine2" TargetControlID="cb2" />
</ItemTemplate>
</asp:Repeater>
</ContentTemplate>
</ajaxToolkit:Accordion>
</ContentTemplate>
</ajaxToolkit:Accordion>
Everything displays correctly. On button click, elsewhere on the page, I am attempting to gather all of the controls and only the accordion controls, some literals, and the hidden fields I am using are being displayed.
Here is the recursive FindControls function I am using:
public static void FindControls(Control start, List<Control> list)
{
list.Add(start);
foreach (Control c in start.Controls)
{
FindControls(c, list);
}
}
This function is never finding the CheckBoxes in order to return them even though it displays correctly.

Dynamically assigning a property in a usercontrol in an ASP.NET repeater control

I currently have a repeater control and inside the itemtemplate I have a usercontrol. This usercontrol renders correctly, but I am trying to assign a dataitem to a property in the repeater control.
<asp:Repeater ID="Repeater1" DataSourceID="EntityDataSource" runat="server">
<ItemTemplate>
<uc1:Request ID="Request1" runat="server" RequestId='<%# Eval("RequestId") %>' />
</ItemTemplate>
RequestId is just an Int32. It just doesn't assign it.
I can put the eval outside of the usercontrol just in the itemtemplate and it correctly outputs the right id.
If I remove the whole eval and just type a number in then it works fine.
Any help appreciated.
[UPDATE] : Issue Solved
I was using an EntityDataSource and this automatically binded to the repeater. It printed out all the information from the database on the screen without any codebehind. But when I put in the code behind Repeater1.DataBind(); it then started to work.
I don't know why, but hey it's solved. It now successfully passes the value through. I imagine it has something to do with the page lifecycle.
If you just bind with repeater collection of int, you need use this:
<uc1:Request ID="Request1" runat="server" RequestId='<%# Container.DataItem %>' />
And don't forget to call DataBind() for repeater or for Page where there is a repeater control.
Are you missing a ' at the end?
change following:
RequestId='<%# Eval("RequestId") %> />
to
RequestId='<%# Eval("RequestId") %>' />
You can implement this by using Repeater control's ItemDataBound event, so that you can set the dynamic property for the control.

How to expose an ITemplate through a User Control?

To make certain form creation easier, we use a modified Formview control that is inside a User Control. This User Control is for a grid and a FormView, you can choose an item in the grid, and a FormView is presented in a modal for viewing/editing:
<I2CL:Grid runat="server" ID="Grid" OnSelecting="Selecting" ShowCreate="true" />
<I2:Modal ID="SFModal" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<I2:FormView runat="server" ID="FVSubForm" DefaultMode="Edit" DataSourceID="DSSubForm" />
<I2:ILDataSource ID="DSSubForm" runat="server" />
</ContentTemplate>
</I2:Modal>
In a page, the control looks like this:
<I2C:TabGrid ID="TG" runat="server" Property="ParentProperty">
<Columns>
<I2:Column Header="Column 1" DataSource="Column1" />
<I2:Column Header="Column 2" DataSource="Column2" />
</Columns>
<EditItemTemplate>
<I2Form:Dropdown ID="Col1" runat="server" SelectedValue='<%# Bind("Column1") %>' List="Column1Options" />
<I2Form:Textbox ID="Col2" runat="server" Text='<%# Bind("Column2") %>' />
</EditItemTemplate>
</I2C:TabGrid>
The problem is the EditItemTemplate we use. The only way I can figure out how to hook it up is to have an ITemplate in the TabGrid control and apply the reference in OnInit:
[PersistenceMode(PersistenceMode.InnerProperty),
TemplateContainer(typeof(FormView))]
public ITemplate EditItemTemplate { get; set; }
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
FVSubForm.EditItemTemplate = EditItemTemplate;
}
The problem with this is that because the reference is to an object in the user control, the EditItemTemplate reference that ties to the dictionary entries in FormView for changes are destroyed, so when you get the dictionary of changes sent to the datasource, they're empty on every postback.
The I2:ILDataSource used here is a custom implementation closest to ObjectDataSource. Instead of a generic object call, it directly calls a GetEntity() in the page (or user control in this case) and a UpdateEntity(obj Entity) to save. Since it's a very specific scenario, we can eliminate 90% of the code in ObjectDataSource.
What I want to be able to do is point the <EditItemTemplate> in the <I2C:TabGrid> directly to the <EditItemTemplate> of the <I2:FormView> inside. Is this possible, or anyone have suggestions of another route to go?
Note: I tried exposing the EditItemTemplate on FVSubForm as a proxy property, but this didn't work because the property is set on the user control before the child control is created, so FVSubForm is null. If this can be worked around, I'm certainly all ears.
One thing you need to do is mark your ITemplate property as supporting two-way databinding:
[TemplateContainer(typeof(FormView), System.ComponentModel.BindingDirection.TwoWay)]
Without this, ASP.NET will not generate the proper code for the page that allows Bind() expressions to work.
I'm not sure if that's all you need, but that's something to try.
David

Categories

Resources