I have many A html tags in my master web page. I would like to replace their HREF values at runtime using code. How to do that? All a tags are tagged with runat="server".
You have to iterate over all the controls in the ControlsCollection and update the Href property of all controls that are of type HtmlAnchor, like this:
private void UpdateTags(Control page)
{
foreach (Control ctrl in page.Controls)
{
if (ctrl is HtmlAnchor)
{
((HtmlAnchor)ctrl).HRef = "myNewlink";
}
else
{
if (ctrl.Controls.Count > 0)
{
UpdateTags(ctrl);
}
}
}
}
You can use HRef property of AncorTag HTML Control to change it.
like this:
<a id="anchor1" runat="server"></a>
In code
void Page_Load(object sender, EventArgs e)
{
anchor1.HRef = "http://www.microsoft.com";
}
HtmlAnchor MyAnchor = (HtmlAnchor)e.Item.FindControl("YourAnchorID");
MyAnchor.HRef = "mypage.aspx";
You should give it an Id and then change the Href property.
<a runat="server" id="link1">link 1</a>
And then:
link1.HRef = "http://stackoverflow.com";
You could also make a CustomControl, extending the Hyperlink-Class and put some Logic into that.
We use it to a custom hyperlink to add Trackingdata to some links.
Related
I have written a project in C# in which I load a HTML webpage if an event occurs during teh course of the project usage.
My issue is that inside my html page, I have a href node inside a tag as such:
<a href="http://pseudo01.hddn.com/vod/demo.flowplayervod/flowplayer-700.flv"
style="display:block;width:inherit;height:inherit;background-color: black;overflow:hidden"
id="player">
</a>
I would like to change the href value programatically by sending a C# variable (called myHrefFile) depending on what the user did.
How can this be done?
you can do something like this
<a href="<%= someMethodThatGetHrefValue() %>"
style="display:block; width:inherit;height:inherit; background-color:black;
overflow:hidden"
id="player">click</a>
call the method that decide what should be href for link .
and put all the logic of deciding href in that method like this
public string someMethodThatGetHrefValue()
{
if(someval == true)
return "http://www.google.com";
else
return "http://www.yahoo.com";
}
Something like this perhaps? This is an Asp.net solution.
<asp:LinkButton ID="LinkBut" runat="server" onclick="LinkBut_Click">Click here</asp:LinkButton></p>
protected void LinkBut_Click(object sender, eventArgs e)
{
string myHrefFile = "";
if(Value.equals(true))
{
myHrefFile = "page1.aspx";
}
else
{
myHrefFile = "page2.aspx";
}
Response.Redirect(myHrefFile );
}
How to check if ContentPlaceHolder is absolutely empty?
In the ContentPlaceHolder have text only, without tags and controls.
Example Page.Master:
<asp:ContentPlaceHolder runat="server" ID="Content" />
Example Test.aspx:
<asp:Content runat="server" ContentPlaceHolderID="Content">
Custom text without controls. Content.Controls.Count is 0 and Content.HasControls is false.
</asp:Content>
What I need to do is that when the placeholder is empty put a default content is in another control.
Overwrite tried twice for the same placeholder but I get error when dynamic load.
You can implement a method that will render the content control into a string, then check the string to find wheahter it contains any non-white space chars:
private bool HasContent(Control ctrl)
{
var sb = new System.Text.StringBuilder();
using (var sw = new System.IO.StringWriter(sb))
{
using(var tw = new HtmlTextWriter(sw))
{
ctrl.RenderControl(tw);
}
}
var output = sb.ToString().Trim();
return !String.IsNullOrEmpty(output);
}
protected void Page_PreRender(object sender, EventArgs e)
{
var placeholder = Master.FindControl("FeaturedContent");
var hasContent = HasContent(placeholder);
}
You need to find the ContentPLaceHolder on the master page first. Then you can cast the first control(which always exists) to LiteralControl and use it's Text property.
So this works as expected from Page_Load of the content-page:
protected void Page_Load(object sender, EventArgs e)
{
var cph = Page.Master.FindControl("Content") as ContentPlaceHolder;
if (contentPlaceHolder != null)
{
string textualContent = ((LiteralControl) cph.Controls[0]).Text;
if (string.IsNullOrEmpty(textualContent))
{
// ...
}
}
}
This seems to have changed, because I am seeing in 4.5 that HasControls DOES return true when there is only literal text in the Content, even a single whitespace. I do something like this in my master page:
<asp:Panel id="SidebarPanel" CssClass="Sidebar" runat="server">
<asp:ContentPlaceHolder id="SidebarContent" runat="server" />
</asp:Panel>
Sub Page_Load(...)
SidebarPanel.Visible = SidebarContent.HasControls
End Sub
This renders the sidebar content, if there is any, inside a <div class="Sidebar"> -- and avoids creating an empty div on the page when there's no content.
I really didn't want to run all the code for a render or risk that maybe some controls might have states that change after being rendered. So I came up with another approach.
public static int ChildrenCount(ContentPlaceHolder placeholder)
{
int total = 0;
total += placeholder.Controls.OfType<Control>().Where(x =>
(!(x is ContentPlaceHolder) && !(x is LiteralControl)) ||
(x is LiteralControl && !string.IsNullOrWhiteSpace(((LiteralControl)x).Text))
).Count();
foreach (var child in placeholder.Controls.OfType<ContentPlaceHolder>())
total += ChildrenCount(child);
return total;
}
For me the text I'd place directly into a Content element would be returned by OfType as a LiteralControl with the appropriate contents. Not only this but my formatting ("\r\n\t") would also be returned the same way. I'd also get ContentPlaceholders for subsequent master pages as they passed the slot in my web pages to the next master page or actual page.
So the task now is to get a count of controls that excludes these ContentPlaceholders and also excludes LiteralControls which are whitespace. This is pretty easy using the is operator. We'll just make sure a given control is neither of those types and then count it, or if it is a Literal we check if the contents are all whitespace or not. The last step is to recursively add the results of the same operation for all child ContentPlaceholders so nested master pages work as expected.
And then finally:
if (ChildrenCount(MyContentPlaceholder) == 0)
MyContentPlaceholder.Controls.Add(new LiteralControl("My default content!"));
My 2 cents:
If it's a constant content you'll have to insert AND there will be no <Content> at all:
<asp:ContentPlaceHolder>
<!-- Anything here will be inserted if there's no Content -->
</asp:ContentPlaceHolder>
I have a ASP.NET bulleted list control that, until today, was created and used only for plain text. A new design request asks that I turn SOME of those items into hyperlinks. Therefore the bulleted list will ultimately need to contain some plain text items, and some hyperlinks. If I change it to DisplayMode=Hyperlink, even if I leave the value blank, the entries that should just be plain text still become clickable links.
One solution that I think I can make work, is to use a Literal control and use HTML (<a href...) on the lines that need to be links. That will entail a little bit of re-working some old code, so before I try that I really want to know if this is possible to do with the existing BulletedList.
EDIT:
I seriously couldn't find anything about this anywhere, and I generally consider myself a pretty good Googler. So for the one or two lost and confused souls who find themselves in the same scenario sometime in the next decade, here is my complete implementation of the excellent answer offered below:
In the page's code-behind:
foreach (SupportLog x in ordered)
{
blschedule.Items.Add(new ListItem(x.Headline, "http://mysite/Support/editsupportlog.aspx?SupportLogID=" + x.SupportLogID));
}
blschedule.DataBind();
Note the DataBind at the end --- this is necessary to fall into the DataBound event:
protected void blschedule_DataBound(object sender, EventArgs e)
{
foreach (ListItem x in blschedule.Items)
{
if (x.Value.Contains("http")) //an item that should be a link is gonna have http in it, so check for that
{
x.Attributes.Add("data-url", x.Value);
}
}
}
In the .aspx page's head:
<script src="<%# ResolveClientUrl("~/jquery/jquery141.js") %>" type="text/javascript"></script>
<script>
$(document).ready(function () {
$('#<%=blschedule.ClientID %> li').each(function () {
var $this = $(this);
var attr = $this.attr('data-url');
if (typeof attr !== 'undefined' && attr !== false) {
$this.html('' + $this.text() + '');
}
});
});
</script>
The if statement is required to make sure to only turn the items that have the "data-url" attribute into links, and not turn ALL items into links.
You may find it's easier to use an <asp:Repeater /> for that task.
Something like:
<asp:Repeater ID="Repeater1" runat="server">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li><%# string.IsNullOrEmpty(Eval("url").ToString()) ? Eval("text") : string.Format("{1}", Eval("url").ToString(), Eval("text").ToString()) %></li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
Hackalicious Way
set the URL value to DataValueField when data binding the BulletedList
use the DataBound event to iterate through the items and add an attribute to each one with a URL value
protected void BulletedList1_DataBound(object sender, EventArgs e)
{
foreach (ListItem i in BulletedList1.Items)
{
if (i.Value.Length > 0)
{
i.Attributes.Add("data-url", i.Value);
}
}
}
use JavaScript/jQuery to apply the necessary markup:
$('[data-url]').each(function() {
var $this = $(this);
$this.html('' + $this.text() + '');
});
didn't test this jQuery but it should be close
I have a page which initially inherited from MastePage.master . And I want to use the same page but with different masterpage(MasterPage2.master) at some other place in my project. For that I am using the following code.
private void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["Update"].ToString() == "New")
{
this.MasterPageFile = "MasterPage2.master";
Content con = new Content();
con = (Content)this.FindControl("Content1");
this.Content1.ContentPlaceHolderID = "ContentPlaceHolder2";
}
}
I am also trying to set the asp content tag's ContentPlaceHolderID to ContentPlaceHolder2 which is from MasterPage2.master. Initially it was ContentPlaceHolder1.
But I am getting null value at con = (Content)this.FindControl("Content1");
Thanks
Page internally stores in private '_contentTemplateCollection' hashtable. it uses ContentPlaceHolderID property as key and stores special class (that will be used to build/initialize Content tag) as a value
- so to change ContentPlaceHolderID value (defined within markup) you need to modify this hashtable, remove old entry linked with old Id and add other entry with new Id
- you need to change ContentPlaceHolderId before creating master page otherwise an exception will be thrown in runtime
- best place to change Ids is Page 'preinit' event and if it is better to change Ids before change master page (if you will change master page at runtime)
To change ContentPlaceHolderID of Content tag, you can use following function in Page PreInit event
public static void AssignContentToNewPlaceHoldersWithinPage(Page pPage, string pOldId, string pNewId)
{
if (pPage == null || string.IsNullOrEmpty(pOldId) || string.IsNullOrEmpty(pNewId))
{
return;
}
// Try to get a reference to private hashtable using fasterflect free reflection library in codeplex (http://fasterflect.codeplex.com/)
// you can replace following line with standard reflection APIs
var lTmpObj = pPage.TryGetFieldValue("_contentTemplateCollection");
if (lTmpObj != null && lTmpObj is Hashtable)
{
var _contentTemplateCollection = lTmpObj as Hashtable;
if (_contentTemplateCollection.ContainsKey(pOldId) && !_contentTemplateCollection.ContainsKey(pNewId))
{
var lTemplate = _contentTemplateCollection[pOldId];
_contentTemplateCollection.Add(pNewId, lTemplate);
_contentTemplateCollection.Remove(pOldId);
}
}
}
function parameter are
pPage is reference to page instance contains content tag
pOldId is ContentPlaceHolderId property value in markup - the Id you want to change
pNewId is the new Id you want to use
I hope that my answer will be useful and I am sorry if my English language is not good
You can dynamically change the Master Page at runtime, but you need to use the same ContentPlaceHolder IDs. That way, your pages will work with either Master Page without adding extra code to change the IDs at runtime.
private void Page_PreInit(object sender, EventArgs e)
{
if (Request.QueryString["Update"].ToString() == "New")
{
this.MasterPageFile = "MasterPage2.master";
}
}
You can even test that your page will work with either Master Page in the Visual Studio design/markup view by changing the MasterPageFile in the <% Page %> directive in the .aspx markup.
The Master Page can be changed by overriding OnPreInit.
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
MasterPageFile = "~/MasterPages/MyOther.Master";
}
But for the ContentPlaceHolders I would suggest to create new ContentPlaceHolders with the same name in both of your MasterPages.
We have a web browser in our Winforms app to nicely display history of a selected item rendered by xslt.
The xslt is writing out <a> tags in the outputted html to allow the webBrowser control to navigate to the selected history entry.
As we are not 'navigating' to the html in the strict web sense, rather setting the html by the DocumentText, I can't 'navigate' to desired anchors with a #AnchorName, as the webBrowser's Url is null (edit: actually on completion it is about:blank).
How can I dynamically navigate to Anchor tags in the html of the Web Browser control in this case?
EDIT:
Thanks sdolphion for the tip, this is the eventual code I used
void _history_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
_completed = true;
if (!string.IsNullOrEmpty(_requestedAnchor))
{
JumpToRequestedAnchor();
return;
}
}
private void JumpToRequestedAnchor()
{
HtmlElementCollection elements = _history.Document.GetElementsByTagName("A");
foreach (HtmlElement element in elements)
{
if (element.GetAttribute("Name") == _requestedAnchor)
{
element.ScrollIntoView(true);
return;
}
}
}
I am sure someone has a better way of doing this but here is what I used to accomplish this task.
HtmlElementCollection elements = this.webBrowser.Document.Body.All;
foreach(HtmlElement element in elements){
string nameAttribute = element.GetAttribute("Name");
if(!string.IsNullOrEmpty(nameAttribute) && nameAttribute == section){
element.ScrollIntoView(true);
break;
}
}
I know this question is old and has a great answer, but this hasn't been suggested yet, so it might be useful for others that come here looking for an answer.
Another way to do it is use the element id in the HTML.
<p id="section1">This is a test section</p>
Then you can use
HtmlElement sectionAnchor = webBrowserPreview.Document.GetElementById("section1");
if (sectionAnchor != null)
{
sectionAnchor.ScrollIntoView(true);
}
where webBrowserPreview is your WebBrowser control.
Alternatively, sectionAnchor.ScrollIntoView(false) will only bring the element on screen instead of aligning it with the top of the page