I have a repeater which dynamically generate tab links using Sitecore (sc:Link) like this:
<asp:Repeater ID="rptTab" runat="server" OnItemDataBound="rptTab_ItemBound">
<ItemTemplate>
<li id= "liTabTest" runat = "server" class="tab-label">
<asp:HyperLink onclick = "javascript: TabClick(this)" runat="server" id="aLink">
<sc:Link ID="hlTabLink" Field="scTabLink" runat="server" ></sc:Link>
</asp:HyperLink>
</li>
</ItemTemplate>
</asp:Repeater>
I manipulate the CSS via JS:
var loadURL;
$(document).ready(function () {
init();
});
function init() {
$("ul#Tab-labels li:first").addClass("TabbedPanelsTabSelected");
};
function TabClick(obj) {
$("ul#Tab-labels li").removeClass("TabbedPanelsTabSelected");
$(obj).addClass("TabbedPanelsTabSelected");
};
Unfortunately, this is not working because each tab is a separate .ASPX page, so the page is getting rendered again and that is why Init() in JS is getting called and CSS is getting executed to the first item everytime.
This is my code behind:
protected void rptTab_ItemBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Item i = e.Item.DataItem as Item;
Link hlTabLink = e.Item.FindControl("hlTabLink") as Link;
hlTabLink.DataSource = i.Paths.FullPath;
hlTabLink.Field = "Title";
HyperLink aLink = e.Item.FindControl("aLink") as HyperLink;
aLink.NavigateUrl = Sitecore.Links.LinkManager.GetItemUrl(i);
}
}
I tried adding CSS through code-behind but it didnt work because I cannot get the index of the tab (which tab is getting selected). Any solution will be appreciated! Thanks!
Don't run javascript for a task that is better (and easier) accomplished in code-behind. Just set the active class for the repeater item where Sitecore.Context.Item matches the name of the tab. Pseudo code inside ItemDataBound:
if(i == Sitecore.Context.Item)
{
HtmlGenericControl li = e.Item.FindControl("liTabTest");
li.Attributes.Add("class","TabPanelTabbedSelected");
}
Not sure if HtmlGenericControl is correct here, or if it has a CssClass property, but I hope you get the idea. If there is no direct representation for li on the server side, you can also bind a string literal or use a Literal control.
The answer to my question is: The repeater is like an array. So I can get the 1st and Last element of a repeater like this:
string currClass = hc.Attributes["class"].ToString();
string count = e.Item.Controls.Count.ToString();
if (e.Item.ItemIndex == 0)
{
currClass += " TabbedPanelsTabSelected";
}
else if (e.Item.ItemIndex.ToString() == count)
{
currClass += " last";
}
In this way I can add a css to my first element and the last element through Repeater.
Related
I have a listview populated from the database. I also have a dynamically calculated value (users inputted postcode relative distance to all database postcode)
I tried adding a label which I can successfully access in the ItemTemplate for the ListView through the ItemDataBound event:
protected void ListView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
if (CategoryList.SelectedIndex == 5)
{
var lb = e.Item.FindControl("lbPostcodeDistance") as Label;
if (!string.IsNullOrEmpty(tbPostcode.Text))
{
lb.Text = "Distance from: " + tbPostcode.Text;
lb.Visible = true;
}
}
}
}
Above works fine, however, I need to dynamically add an actual value to lb.Text.
The value is calculated in my public IEnumerable<...> ListView1_GetData(), here is a snippet of code:
var inRangeWalks = new List<InRangeWalks>();
foreach (var walk in grabAllWalks)
{
double dis = //calculation here
if (dis <= radius)
{
inRangeWalks.Add(new InRangeWalks(dis, walk));
}
}
inRangeWalks.Sort((x, y) => x.DistanceFromPostcode.CompareTo(y.DistanceFromPostcode));
}
return inRangeWalks.Select(x => x.Walk); //ListView only wants walks, thus returned ordered Walks.
The code above works perfectly, but I need to add the dis value to each item in the ItemTemplate. I've been trying to do it using the ItemDataBound event but I am not sure if this is correct, or even possible.
Here is my ItemTemplate:
<ItemTemplate>
<div class="row">
...
<h6><b>Location:</b> <%# Item.Location%>, <%# Item.Postcode%></h6>
<asp:Label ID="lbPostcodeDistance" runat="server" Text="Label" Visible="false"></asp:Label>
</div>
</ItemTemplate>
How else could I show an additional dynamically calculated value, exactly where the label is in the ItemTemplate?
Ok I actually ended up using Rahul's advice in the comments, and made my ListView use my custom data source.
Was a little bit of a pain to get it up and running but it's now working great!
If someone wants to implement their own data structure, just remember on the ASPX page change the ItemType to the new structure i.e. ItemType="MyProject.Folder.ClassName". And then you can access the property with model binding like: text=<%# Item.MyObject.Property %>
I have a need to create a small window inside of a ASP.NET Web Page(aspx) which displays a list of usernames, when you click the username, I need a new broswer window (not tab) to open up to a specific size. I can handle opening the new browser window assuming whatever control I use gets me into a code behind function where I can call....
string url = "http://www.dotnetcurry.com";
ScriptManager.RegisterStartupScript(this, this.GetType(), "OpenWin", "<script>openNewWin ('" + url + "')</script>", false);
Here's the markup that's in the page for the link.
<script language="javascript" type="text/javascript">
function openNewWin(url) {
var x = window.open(url, 'mynewwin', 'width=600,height=600,toolbar=1');
x.focus();
}
</script>
1.) What controls should I be using for this problem, what does the structure look like after I get the respective usernames back from the database?
Here's the closest I've come...This code uses an ASP.NET Bulleted List which I'm trying to bind to a list of HTML links which I would like to instead not POINT anywhere, but get me to the codebehind. Instead this Code actually renders on the page as the HTML (it isn't parsed into hyperlinks..)
protected void Page_Load(object sender, EventArgs e)
{
UsersBulletedList.DataSource = theContext.GetOnlineFavorites(4);
UsersBulletedList.DataBind();
}
public IQueryable<String> GetOnlineFavorites(int theUserID)
{
List<String> theUserList = new List<String>();
IQueryable<Favorite> theListOfFavorites= this.ObjectContext.Favorites.Where(f => f.SiteUserID == theUserID);
foreach (Favorite theFavorite in theListOfFavorites)
{
string theUserName = this.ObjectContext.SiteUsers.Where(su => su.SiteUserID == theFavorite.FriendID && su.LoggedIn == true).FirstOrDefault().UserName;
yourOnlineFavorites.Add("<a href='RealTimeConversation.aspx?UserName=" + theUserName + "'>" + theUserName + "</a>");
//this needs to help me get into a codebehind method instead of linking to another page.
}
return yourOnlineFavorites.AsQueryable();
}
I would create a Repeater on your page and bind your results from the GetOnlineFavorites method. Inside the Repeater, place a LinkButton with a ItemCommand event that adds your script to the page.
Markup:
<asp:Repeater ID="repeater" runat="server" OnItemCommand="repeater_ItemCommand">
<ItemTemplate>
<asp:LinkButton runat="server" ID="linkButton"
Text='<%# Eval("PropertyFromBindingCollection") %>'
CommandName="OpenWindow"
CommandArgument='<%# Eval("AnotherProperty") %>' />
</ItemTemplate>
</asp:Repeater>
In here, the Text property of the LinkButton and the CommandArgument of the Repeater would be set to some properties from your collection.
Code Behind:
protected void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
repeater.DataSource = theContext.GetOnlineFavorites(4);
repeater.DataBind();
}
}
protected void repeater_ItemCommand(object sender, RepeaterCommandEventArgs e)
{
if(e.CommandName == "OpenWindow")
{
string arg = e.CommandArgument; // this could be the url, or a userID to get favorites, or...?
//Your open window script
}
}
Now, when the user clicks one of the LinkButtons, it will fire the ItemCommand event for the Repeater, check the CommandName (set on the LinkButton), and then get the CommandArgument set on the LinkButton. If you set the CommandArgument as a URL, you can use that in your OpenWin script, otherwise use whatever data you set as the argument to get the URL you want to open.
Question pretty much says it all. On my aspx page I have a GridView and under Columns I have a bunch of BoundFields, one of which is a TemplateField
<asp:TemplateField HeaderText = "Status">
<ItemTemplate>
<asp:HyperLink ID = "HyperLink1" runat = "server" Target = "_blank"
NavigateUrl = '<%# Eval("URL") %>'
Text = '<%#Eval("Status") %>'>
</asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
Now, I want this Hyperlink to map to a different image, depending on what the text is evaluated to. For example, 'Success' displays a big ol' smiley face instead, 'Failed' displays a frowney face, and so on. How can I achieve this?
Thanks for looking.
You can put an image in the hyperlink like
<img src='/images/status/<%#Eval("Status") %>.jpg' />
and just make a different image for each status by name. Otherwise you'll probably have to do something on the DataBind event.
Try this
protected void myGridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
HyperLink HyperLink1 = e.Row.FindControl("HyperLink1");
if(SomeText == "Success")
HyperLink1.NavigateUrl = "Url to Smiley";
else
HyperLink1.NavigateUrl = "Url to Frowney";
}
}
HyperLink HyperLink1 = (HyperLink)e.Row.FindControl("HyperLink1");
switch (HyperLink1.Text)
{
case "Completed":
HyperLink1.ImageUrl = "Images\\Success.png";
HyperLink1.ToolTip = "Completed";
etc
The ToolTip property maps to the alternate text for the image.
Thanks to codingbiz for getting me started.
If you are trying to set the ImageUrl property I suggest using the RowDataBound event. The handler method could would look something like:
protected void questionsGridView_RowDataBound(object sender, System.Web.UI.WebControls.GridViewRowEventArgs e)
{
DataSourceDataType row;
HyperLink hyperLink1;
if (e.Row.RowType == DataControlRowType.DataRow & e.Row.DataItem is DataSourceDataType)
{
row = (DataSourceDataType)e.Row.DataItem;
hyperLink1 = (HyperLink)e.Row.FindControl("HyperLink1");
hyperLink1.ImageUrl = (row.IsSuccess) ? "~/images/success.png" : "~/images/failure.png";
}
}
Another trick I have used is altering the data object you are binding to to have a property which indicates the URL to use:
partial class DataSourceDataType
{
public string SuccessImgURL
{
get
{
return (IsSuccess) ? "~/images/success.png" : "~/images/failure.png";
}
}
}
Then you bind to that property.
Note: IsSuccess would need to be replaced with your own field name or boolean condition.
I often use this with LINQ to SQL objects, so adding properties can be done in a separate file using partial classes. This way you do not have to worry about the LINQ to SQL tools removing your additions.
I have a GridView with PageSize = 20 (20 rows) but it can show only 10 rows without a vertical scrollbar appearing.
My problem is that when a postback occurs, it jumps to top row of the grid even though I selected a different row. I would like to scroll to the selected row. How can I do this?
Add MaintainScrollPositionOnPostback in your page directive.
<%# Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" MaintainScrollPositionOnPostback ="true"%>
Another way, use a scrollTop method of the DIV that wraps your GridView:
private void ScrollGrid()
{
int intScrollTo = this.gridView.SelectedIndex * (int)this.gridView.RowStyle.Height.Value;
string strScript = string.Empty;
strScript += "var gridView = document.getElementById('" + this.gridView.ClientID + "');\n";
strScript += "if (gridView != null && gridView.parentElement != null && gridView.parentElement.parentElement != null)\n";
strScript += " gridView.parentElement.parentElement.scrollTop = " + intScrollTo + ";\n";
ScriptManager.RegisterClientScriptBlock(this.Page, this.GetType(), "ScrollGrid", strScript, true);
}
EDIT:
This won't work for several reasons:
1) if the gridView is inside a NamingContainer control, like a Panel, because the Id on the client side won't be the ClientId. You need to use the UniqueId of teh control instead.
2) you can't trust the row height to calculate the scroll position. If the text in any column wraps to more than one line, or any row contains something higher than the style, the size of the row will be different
3) different browsers can have different behaviors. You're better of using jQuery scrollTop() and scroll() functions. To use them, you must use scrollTop on client side and set the value of a HiddenControl that can be read on server side to reset the position. You can't get the height of the rows in the browser until they are rendered on client side.
This code in the RowDataBound event handler for the gridview worked for me:
protected void dgv_usersRowDatabound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowIndex == intEditIndex)
{
DropDownList drpCategory = e.Row.FindControl("drpCategory") as DropDownList;
drpCategory.Focus();
}
}
The Gridview contains a dropdownlist in each row as an EditItemTemplate.
This worked for me, and required no ASP.NET AJAX, UpdatePanel or cookie, and a lot less JavaScript than other solutions I've seen.
<input type="hidden" runat="server" id="hdnScroll" value="0" />
<div style="height:600px; overflow-x:hidden; overflow-y:scroll">
<asp:GridView runat="server" ID="myGridView" OnRowDataBound="myGridView_RowDataBound" OnSelectedIndexChanged="myGridView_SelectedIndexChanged">
...
</asp:GridView>
</div>
Then
protected void myGridView_SelectedIndexChanged(object sender, EventArgs e) {
//if(gr != null) gr.SelectedRow.Cells[0].Focus(); // Only works on an editable cell
hdnScroll.Value = (myGridView.SelectedIndex * (int)myGridView.RowStyle.Height.Value).ToString();
}
Finally back in the .aspx, to run upon postback
<script type="text/javascript">
$(function() {
document.getElementById('<%=myGridView.ClientID%>').scrollTop = $('#hdnScroll').val();
});
When the page first load i have a label who has 0 or 1. Look at the code and you will se what i trying to do. But it don't work because the page allready loaded.
protected void rptBugStatus_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lblName = e.Item.FindControl("lblBugStatus") as Label;
if (lblName.Text == "1")
{
lblName.Text = lblName.Text + "Under arbete";
}
else if (lblName.Text == "0")
{
lblName.Text = "Fixad";
}
else { }
}
}
You really want to avoid this type of coding if at all possible. This will quickly grow into an unmaintainable web site.
Query the underlying data instead of GUI elements.
where you put your code? and be cautious e.Item.FindControl("lblBugStatus") as Label; may return null
it's just work fine to fine the control. But i figure out another way to get out the data i want. That i'am going to is fix the xml structur better.
You may have resolved this by now, but I think the problem with the code as you posted it is this:
Label lblName = e.Item.FindControl("lblBugStatus") as Label;
Because you are referencing a control in a repeater, the controls inside each repeater item are named dynamically based on their context. Most likely the name of the control is something like:
"rptBugStatus$repeaterItem0$lblBugStatus"
To find out the exact name, hard code a value, run the page in a browser, and look at the HTML output (via "View Source" in the browser menu). You should be able to scroll down and see your repeater (it will be rendered as a <table> tag), its items, and the controls living inside each item. The IDs/Names will be set and you can copy/paste them into your FindControl method.
Hope this helps,
Nate
Ok, I am taking the assumption you have set this label (assuming to be in the repeater, from your code) to have a value - I have tried databinding to something exactly the same, using the below code.
protected override void OnPreRender(EventArgs e)
{
base.OnLoad(e);
List<string> strList = new List<string>();
strList.Add("1");
rptBugStatus.DataSource = strList;
rptBugStatus.DataBind();
}
protected void rptBugStatus_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Label lblBugStatus = e.Item.FindControl("lblBugStatus") as Label;
// have added this just so we are actually setting the text property on the bug status
// - i have assumed you do this.
lblBugStatus.Text = e.Item.DataItem.ToString();
if (lblBugStatus.Text.Equals("1"))
{
lblBugStatus.Text = lblBugStatus.Text + "Under arbete";
}
else if (lblBugStatus.Text.Equals("0"))
{
lblBugStatus.Text = "Fixad";
}
}
}
With the aspx being
<asp:Repeater runat="server" ID="rptBugStatus" OnItemDataBound="rptBugStatus_ItemDataBound">
<ItemTemplate>
<asp:Label ID="lblBugStatus" runat="server"></asp:Label>
</ItemTemplate>
</asp:Repeater>
And I have no problems.
I get the below on the page.
1Under arbete
I think you are going to need to post more code if you have hidden any away from us :)
Tim