In asp net code behind I need to know the id of the parent html control of a asp control.
For example:
<div id="popuplogin" class="popuplogin">
<asp:LinkButton ID="btnRegister" OnClick="btnRegister_Click1" runat="server">LinkButton</asp:LinkButton>
Now in code behind I would like to find the id of the div control which is the parent of the linkbutton (asp control).
For example:
protected string FindParentHtmlId(Control c)
{
return etc..
}
If you want to find that div, you first need to add runat=server to be able to find it in code behind.
<div id="popuplogin" class="popuplogin" runat="server">
<asp:LinkButton ID="btnRegister" runat="server">LinkButton</asp:LinkButton>
</div>
Then you can do something like this:
protected string FindParentHtmlId(Control c)
{
var parent = c.Parent;
if (parent != null)
return parent.ID;
else
return "No parent found";
}
Related
How can I append some html to a div with a specific class name?
frontend:
<div class="school-team-popup"></div>
backend:
StringBuilder _html = new StringBuilder();
_html.AppendFormat("<li>Hi there</li>");
I would like to append _html inside the school-team-popup div. How can I do this from the backend?
I'm going to explain the Web Forms way of doing things.
If you have some static markup that you want to selectively show/hide on your page, that's generally accomplished by setting the Visible property of the control.
<%-- This is in your ASPX markup (.aspx) --%>
<asp:Panel runat="server" id="HelloWorldPanel">
<p>Hello, world!</p>
</asp:Panel>
//This is in your code behind (.aspx.cs)
//hide the panel
HelloWorldPanel.Visible = false;
//show the panel
HelloWorldPanel.Visible = true;
If you're trying to grab dynamic data from some other source and display it on the page, you would declare the markup on your page to show this data, and then bind the data to the markup. There are many controls you can bind data to.
One example of a control you can bind data to is a repeater. Repeaters are good when you want tight control over the markup that gets rendered on the page. You bind them to some enumerable object such as a List<T> and then it will repeat some markup for each element in the enumerable object.
//This is in your project somewhere
namespace MyNamespace
{
public class Product
{
public int Id { get; set; }
public int Name { get; set; }
}
}
<%-- This is in your ASPX markup (.aspx) --%>
<ul>
<asp:Repeater runat="server" id="ProductRepeater" ItemType="MyNamespace.Product">
<ItemTemplate>
<li><%#: Item.Id %> - <%#: Item.Name %></li>
</ItemTemplate>
</asp:Repeater>
</ul>
//this is in your code behind (.aspx.cs)
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostback)
{
List<Product> products = MyDataLayer.GetProducts();
ProductRepeater.DataSource = products;
ProductRepeater.DataBind();
}
}
In the design of web form I have four divs
divGeneralDetails
divLanguageDetails
divLinkDetails
divOperationalDetails
Divs mentioned above are displayed vertically in the form.
My question is.
Depending on value in query string, i will have to change the order in which divs are displayed.
In my Page_Load event
string FirstDiv = Request.QueryString["id"];
if value of FirstDiv is equal to "General"
then order should be
- divGeneralDetails
- divLanguageDetails
- divLinkDetails
- divOperationalDetails
if value of FirstDiv is equal to "Operational"
then order should be
- divOperationalDetails
- divGeneralDetails
- divLanguageDetails
- divLinkDetails
How do I set this in Page_Load event. Any help will be highly appreciated.
Thanks
You can use Panel.
Example:
<asp:Panel ID="panelMain" runat="server">
<asp:Panel ID="divGeneralDetails" runat="server"></asp:Panel>
<asp:Panel ID="divLanguageDetails" runat="server"></asp:Panel>
<asp:Panel ID="divLinkDetails" runat="server"></asp:Panel>
<asp:Panel ID="divOperationalDetails" runat="server"></asp:Panel>
</asp:Panel>
And then rearrange it add code behind:
panelMain.Controls.Clear();
panelMain.Controls.Add(divOperationalDetails);
panelMain.Controls.Add(divGeneralDetails);
panelMain.Controls.Add(divLanguageDetails);
panelMain.Controls.Add(divLinkDetails);
If you want to do it server-side, then for good working of ViewState (if it is being used) the Divs would have to be added in the desired order using Page.Controls.Add() in the PreInit event of the Page. Any later may throw off ViewState.
A totally different approach would be to use jQuery in the browser to manipulate the Divs, see the snippet below for one way to achieve this:
function moveOperationalToTop() {
var specialId = "divOperationalDetails";
var $main = $("#divMain");
var $divs = $main.find('div');
$main.empty();
$divs.each(function() {
if (this.id == specialId) $main.append($(this));
});
$divs.each(function() {
if (this.id != specialId) $main.append($(this));
});
}
#divOperationalDetails {
color: red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="divMain">
<div id="divGeneralDetails">divGeneralDetails</div>
<div id="divLanguageDetails">divLanguageDetails</div>
<div id="divLinkDetails">divLinkDetails</div>
<div id="divOperationalDetails">divOperationalDetails</div>
</div>
<button onclick="moveOperationalToTop()">Move Operational to top</button>
I have a function in the C# code behind of a Sitecore sublayout that returns a string that looks like this:
public string getProductTitle()
{
Item productItem = itemHelper.GetItemByPath(currentItemPath);
Sitecore.Data.Fields.ImageField imgField = ((Sitecore.Data.Fields.ImageField)productItem.Fields["Logo"]);
if (imgField.Value != "")
{
return "<sc:Image CssClass=\"product-image ng-scope\" Field=\"Logo\" runat=\"server\" />";
}
string productTitle = "";
productTitle = productItem["Produkt Titel"];
return "<div class=\"product-name ng-binding ng-scopen\" ng-if=\"!currentProduct.imageNameHome\">" + productTitle + "</div>";
}
And in the ascx I call this fuction:
<%= getProductTitle() %>
The problem is that in the end this is what I'm getting in HTML at runtime:
"<sc:Image CssClass=\"product-image ng-scope\" Field=\"Logo\" runat=\"server\" >";
The / at the end is missing, which breaks the whole line and no image is shown. The
I also tried this:
string a = WebUtility.HtmlEncode("<sc:Image CssClass=\"product-image ng-scopen\" Field=\"Logo\" runat=\"server\" />");
return WebUtility.HtmlDecode(a);
and this:
return #"<sc:Image CssClass=""product-image ng-scopen"" Field=""Logo"" runat=""server"" />";
With the same result.
Am I missing something here? How can I fix this?
I cannot see this working due to the ASP.NET page life cycle.
Sitecore controls are like normal user controls and they run on the server side - returning them as a string will be too late in the page lifecycle for them to render.
I would place the <sc:Image /> control in the ascx page or use a FieldRenderer object to get the HTML from Sitecore
Sitecore.Web.UI.WebControls.FieldRenderer.Render(myItem, "MyFieldName", "disable-web-editing=true");
You can then use logic to show or hide the Image Field and title control based on you requirements. This assumes you are using the Sitecore Context Item.
Replace the <%= getProductTitle() %> with
<sc:Image runat="server" ID="imgLogo" Field="Logo" />
<asp:Placeholder runat="server" ID="phTitle">
<div class=\"product-name ng-binding ng-scopen\" ng-if=\"!currentProduct.imageNameHome><sc:Text runat="server" ID="title" Field="Produkt Titel"/></div>
</asp:Placeholder>
Then in the code behind Page Load method
var currentItem = Sitecore.Context.Item;
if(string.IsNullOrEmpty(currentItem["Logo"])
{
imgLogo.Visible=False;
}
if(string.IsNullOrEmpty(currentItem["Produkt Titel"])
{
phTitle.Visible=False;
}
More information here:
http://gettingtoknowsitecore.blogspot.co.uk/2010/01/displaying-field-values-using-server.html
Since you have two alternate ways you wish to present your information, I would consider moving your controls and HTML to your markup file (ASCX) and then wrapping the segments in asp:placeholder controls.
<asp:placeholder id="imageTitle" runat="server" Visible="false">
<sc:Image CssClass="product-image ng-scope" Field="Logo" runat="server" />
</asp:placeholder>
<asp:placeholder id="textTitle" runat="server>
<div class="product-name ng-binding ng-scopen" ng-if="!currentProduct.imageNameHome">
<asp:Literal id="productTitleLiteral" runat="server" />
</div>;
</asp:placeholder>
You can then toggle the visibility of the placeholder in your code behind during page load.
public void Page_Load{
Item productItem = itemHelper.GetItemByPath(currentItemPath);
Sitecore.Data.Fields.ImageField imgField = ((Sitecore.Data.Fields.ImageField)productItem.Fields["Logo"]);
if (imgField.Value != "")
{
this.imageTitle.Visible = true;
this.textTitle.Visible = false;
}
else {
this.imageTitle.Visible = false;
this.textTitle.Visible = true;
this.productTitleLiteral.Text = productItem["Produkt Titel"];
}
}
This will allow you to ensure proper encapsulation of business logic versus presentation markup, and will work better with the .NET lifecycle.
I have a master page file that contains a 2 menu's in a 2 panel controls.
I also use a control to check if user is logged in and get the type of user.
Deppending on the type I want to show / hide the panel. The control itself is not referenced in the master page but dynamically through the CMS System.
I want to use findcontrol in the user control to find the panel control in the master page. I have tried different methods but all come back with null.
The content placeholder in the master page is
asp:Content runat="server" ContentPlaceHolderID="PHMainBlock"
and the control is called
asp:Panel ID="NormalUser" runat="server"
I have tried using the code....
Panel ph = (Panel)Page.Master.FindControl("NormalUser");
ph.Visible = false;
but brings back null, any help?
thanks..
You could create a public property in you Master Page i.e
public bool ShowPanel
{
set
{
NormalUser.Visible = value;
}
}
And call it like this
if (Page.Master is NameOfMasterPage)
{
((NameOfMasterPage)Page.Master).ShowPanel = false;
}
Because the Panel control is inside a ContentPlaceHolder control, you must first get a reference to the ContentPlaceHolder and then use its FindControl method to locate the TextBox control.
ContentPlaceHolder mpContentPlaceHolder;
Panel pn;
mpContentPlaceHolder = (ContentPlaceHolder)Master.FindControl("PHMainBlock");
if(mpContentPlaceHolder != null)
{
pn = (Panel) mpContentPlaceHolder.FindControl("NormalUser");
pn.Visible = false;
}
http://msdn.microsoft.com/en-us/library/xxwa0ff0.aspx
Here's how I do something similar and it works fine:
if (Page.Master != null)
{
var tempPanel = Page.Master.FindControl("MessagePanel") as UpdatePanel;
if (tempPanel != null)
tempPanel.Visible = true;
var temp = Page.Master.FindControl("MessageForUser") as MessageToUser;
if (temp != null)
temp.PostWarningMessage(message, msgInterval);
}
However, I have "MessagePanel" and "MessageForUser" as controls right above the ContentPlaceHolder. Here's my markup:
<asp:UpdatePanel runat="server" Visible="true" ID="MessagePanel" >
<ContentTemplate>
<msg:MainMessage ID="MessageForUser" runat="server" Visible="true" />
<br />
</ContentTemplate>
</asp:UpdatePanel>
<asp:ContentPlaceHolder ID="cphContent" runat="server" Visible="true">
</asp:ContentPlaceHolder>
If you have your Panel inside of a tag, then you should be able to reference the panel without needing Page.Master.FindControl.
One way would be to solve this problem with javascript (jquery):
$('.NormalUser').hide();
http://api.jquery.com/hide/
I'm trying to achieve something google isn't able to give answer. I'm trying to create an asp.net usercontrol that when I put content into it's open close tag will include it for me to be still able to acess it's content by ID from the Parent. Here is an exemple of what I want to achieve.
Usercontrol:
<%# Control Language="C#" AutoEventWireup="true" CodeFile="ctrlGENE_CollapsiblePanel.ascx.cs"
Inherits="Controls_GenericsControls_ctrlGENE_CollapsiblePanel" %>
<asp:Panel ID="pnlHeader" CssClass="SnapPanelHeader" runat="server">
<h3>
<asp:Literal ID="litTitle" Text='<%# Text %>' runat="server" />
</h3>
<div class="SnapPanelHeader-img">
<img id="imgOpenClose" src="/images/application/close.jpg" alt="" />
</div>
</asp:Panel>
<asp:PlaceHolder runat="server" ID="pnlContent">
// **HERE I WANT TO INCLUDE THE INSIDE MARKUP**
</asp:PlaceHolder>
<act:CollapsiblePanelExtender runat="server" TargetControlID="pnlContent" ImageControlID="imgOpenClose"
ExpandControlID="imgOpenClose" CollapseControlID="imgOpenClose" CollapsedImage="/images/application/open.jpg"
ExpandedImage="/images/application/close.jpg" CollapsedSize="0" TextLabelID="litTitle">
</act:CollapsiblePanelExtender>
Parent Page that include control :
<uc:MyUserControl ID="clpTest" runat="server">
<asp:Literal ID="litText" runat="server" />
</uc:MyUserControl>
Like this I would be able in the Parent.cs file to do :
litText.Text = "Anything";
I know we can achieve something similiar with the ITemplate interface as show here : http://msdn.microsoft.com/en-us/library/36574bf6.aspx
That would look like this:
<uc:MyUserControl ID="clpTest" runat="server">
<ItemTemplate>
<asp:Literal ID="litText" runat="server" />
</ItemTemplate>
</uc:MyUserControl>
But If I do this I wouldn't be able to access the property of litText and the only way I could reach it is with a FindControl, which I want to avoid.
Anyone have a hint on this if I can reach my goal one way or another?
Thank you
Ok I fixed it here is the solution I used :
In MyUserConstrol.ascx file I have put a placeholder where I wanted innerHTML to show :
<asp:PlaceHolder runat="server" ID="plhContent" />
Then in the MyUserControl.ascx.cs file I added those attribute to the class:
[ParseChildren(false)]
[PersistChildren(true)]
And I added to the file this:
public void RegisterUpdatePanel(UpdatePanel panel)
{
MethodInfo m =
(from methods in typeof (ScriptManager).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
where methods.Name.Equals("System.Web.UI.IScriptManagerInternal.RegisterUpdatePanel")
select methods).First();
m.Invoke(ScriptManager.GetCurrent(Page), new object[] {panel});
}
protected override void CreateChildControls()
{
for (int i = 0; i < Controls.Count; i++)
if (Controls[i] is MyLastControl)
while (i + 2 < Controls.Count)
{
// In cas there is an updatepanel in the control we are moving
// We are registering an event to register the updatepanel
// to the scriptmanager again
SearchUpdatePanel(Controls[i + 2]);
plhContent.Controls.Add(Controls[i + 2]);
}
base.CreateChildControls();
}
private void SearchUpdatePanel(Control control)
{
if (control is UpdatePanel)
control.Unload += updPnl_Unload;
foreach (Control childcontrol in control.Controls)
SearchUpdatePanel(childcontrol);
}
protected void updPnl_Unload(object sender, EventArgs e)
{
RegisterUpdatePanel((UpdatePanel) sender);
}
Note that I named my last control in the ascx file myLastContol to know what was the control before the innerHTML injection since I don't know what I'm receiving. The the procedure basically say loop in the controls in the UserControl, when you will reach the end of UserControl, everything after is innerHTML from parent so take those and move them to the placeholder where I want them.
I hope this will help someone.
Here is some sources I used to achieve my goal :
Registering UpdatePanel
Add a public property in the user control's code behind file. If you need design time support there's more work involved, but for simple scenarios like the one you outlined it should be enough.
Then just access it in the parent page to set the value and read it in the user control and use that value to render whatever you need there.