Dynamically insert non-database value in ItemTemplate for ListView - c#

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 %>

Related

Checkbox List evaluating all checkmarks as false

I have a simple checkbox list and I'm using a for statement to retrieve the selected values into one string. This has to be simple, but everything is returning false when it evaluates if it is selected.
ASP Code
<asp:CheckBoxList runat="server" ID="ckblInterests" ClientIDMode="Static" RepeatColumns="2" />
ASP.NET Code:
string interests = "";
for (int i = 0; i < ckblInterests.Items.Count; i++)
{
if (ckblInterests.Items[i].Selected)
{
interests += ckblInterests.Items[i].Value + ", ";
}
}
}
The inside if statement evaluates as false each time it loops through. It does count 10 items in the list correctly. I'm stumped at something so simple. Can someone help me identify what might be causing the if statement to return false?
You have code that's dynamically adding the checkboxes to the list on page load (or some other event). This is resulting in the state of those checkboxes being cleared and re-added on each postback. Your page load should probably have an if(!page.ispostback) around that section so that you aren't clearing the content.
With the Following Code (Mostly yours)
Aspx
<div>
<asp:CheckBoxList runat="server" ID="ckblInterests" ClientIDMode="Static" RepeatColumns="2">
<asp:ListItem>Awesome</asp:ListItem>
<asp:ListItem>Tasty</asp:ListItem>
<asp:ListItem>Terrible</asp:ListItem>
</asp:CheckBoxList>
</div>
<asp:Button runat="server" ID="test" OnClick="test_Click" />
<asp:Label runat="server" ID="label"></asp:Label>
c#
protected void test_Click(object sender, EventArgs e)
{
string interests = "";
for (int i = 0; i < ckblInterests.Items.Count; i++)
{
if (ckblInterests.Items[i].Selected)
{
interests += ckblInterests.Items[i].Value + ", ";
}
}
this.label.Text = interests;
}
I was able to produce the following. This is of course after clicking the button.
Are you binding to a datasource that you have not mentioned?
make sure while binding the checkboxlist in page load you have set this check if (!Page.IsPostBack) { ...bind your data }
this should do the trick
I think you need to check the CHECKED property, not SELECTED.

How do I replace a Hyperlink in a Gridview Column with an image, depending on the text in the column?

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.

On Postback, the DataTable data source for a Repeater is empty?

Background
I have a User Control (an .ascx file) which is being dynamically inserting into an asp:PlaceHolder control on a page. That User Control contains an asp:Repeater, which I'm binding to a DataTable.
Theoretically, on the User Control's first load the DataTable is initialized and 3 empty rows are added. A button on the User Control adds additional empty rows to the Repeater, one at a time.
Problem
The issue is that after any PostBack event on the page (namely the button in this example being clicked), the DataTable for the Repeater is empty.
User Control (.ascx)
(simplified)
<asp:TextBox ID="controlOutsideRepeater" runat="server" />
<asp:Repeater ID="myRepeater" runat="server">
<ItemTemplate>
<p><asp:Textbox ID="firstControlInRepeater" runat="server" text='<%# DataBinder.Eval(Container.DataItem, "A") %>' /></p>
<p><asp:Textbox ID="secondControlInRepeater" runat="server" text='<%# DataBinder.Eval(Container.DataItem, "B") %>' /></p>
</ItemTemplate>
</asp:Repeater>
<asp:LinkButton ID="addItemButton" runat="server" Text="Add Item" onclick="addNewItem" />
Code Behind (.ascx.cs)
(also simplified)
public DataTable items {
get {
object i = ViewState["items"];
if (i == null) {
DataTable t = new DataTable();
t.Columns.Add("A");
t.Columns.Add("B");
// add 3 blank items/rows:
t.Rows.Add(t.NewRow());
t.Rows.Add(t.NewRow());
t.Rows.Add(t.NewRow());
ViewState["items"] = t;
return t;
} else {
return (DataTable)i;
}
set { ViewState["items"] = value; }
}
protected void Page_Init(object sender, EventArgs e) {
myRepeater.DataSource = this.items;
myRepeater.DataBind();
}
public void addNewItem(object sender, EventArgs e) {
DataRow r = this.items.NewRow();
this.items.Rows.Add(r);
myRepeater.DataBind();
}
Behavior
The first time the UserControl is loaded, the Repeater contains 3 empty items: good! However, after entering some text in the textboxes both inside and outside the repeater and clicking the "Add Item" LinkButton, the page does a refresh/postback and shows 4 empty items, however the textbox -outside- the Repeater retains it's text. Clicking the "Add Item" LinkButton again also performs a postback and still shows 4 empty items, yet the TextBox outside the Repeater again retains it's text.
My Crazy Guess
I've tried wrapping the Repeater databinding in a (!Page.IsPostBack), but this prevented the Repeater from -ever- being bound, as the UserControl is only programmatically added to the page after a PostBack (a button on the Page adds the UserControl on a click, and then the Page checks each PostBack to see if there should be a user control present and re-adds it to the Page if needed). So I'm guessing there's a problem with the Page re-creating the User Control on every PostBack, but can't explain why the TextBox outside the Repeater would retain it's value, and why the ViewState doesn't seem to remember my item (on each postback ViewState["items"] is null and gets re-built within the getter).
HELP!
The problem is you are data binding every single request when really you only want to data bind on the first request. Since you don't data bind on the first page load, you will have to check if you are data bound in a way other than !Page.IsPostBack. You could add a property to your user control to handle this and then check against that every page load / page init.
Update: With more details from comments
I see your AddItem() now. I've had problems using viewstate this way though I'm not entirely sure why. I've had to do it more like the following:
public void addNewItem(object sender, EventArgs e) {
DataTable theItems = this.items;
DataRow r = theItems.NewRow()
theItems.Rows.Add(r);
this.items = theItems
myRepeater.DataBind(); //I'm not sure if this belongs here because of the reasons said before
}

ASP.NET using Bind/Eval in .aspx in If statement

in my .aspx I'm looking to add in an If statement based on a value coming from the bind. I have tried the following:
<% if(bool.Parse(Eval("IsLinkable") as string)){ %>
monkeys!!!!!!
(please be aware there will be no monkeys,
this is only for humour purposes)
<%} %>
IsLinkable is a bool coming from the Binder. I get the following error:
InvalidOperationException
Databinding methods such as Eval(), XPath(), and Bind() can only
be used in the context of a databound control.
You need to add your logic to the ItemDataBound event of ListView. In the aspx you cannot have an if-statement in the context of a DataBinder: <%# if() %> doesn't work.
Have a look here: http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listview.itemdatabound.aspx
The event will be raised for each item that will be bound to your ListView and therefore the context in the event is related to the item.
Example, see if you can adjust it to your situation:
protected void ListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
if (e.Item.ItemType == ListViewItemType.DataItem)
{
Label monkeyLabel = (Label)e.Item.FindControl("monkeyLabel");
bool linkable = (bool)DataBinder.Eval(e.Item.DataItem, "IsLinkable");
if (linkable)
monkeyLabel.Text = "monkeys!!!!!! (please be aware there will be no monkeys, this is only for humour purposes)";
}
}
I'm pretty sure you can do something like the following
(Note I don't have a compiler handy to test the exact syntax)
text = '<%# string.Format("{0}", (bool)Eval("IsLinkable") ? "Monkeys!" : string.Empty) %>'
Yes this is c# and your using vb.net, so you'll need to use vb syntax for a ternary operator.
Edit - was able to throw into into a simple data bind situation, worked like a charm.
You can use asp:PlaceHolder and in Visible can put eval. Like as below
<asp:PlaceHolder ID="plc" runat="server" Visible='<%# Eval("IsLinkable")%>'>
monkeys!!!!!!
(please be aware there will be no monkeys, this is only for humour purposes)
</asp:PlaceHolder>
OMG this took entirely too long to figure out...
<asp:PlaceHolder runat="server" Visible='<%# Eval("formula.type").ToString()=="0" %>'>
Content
</asp:PlaceHolder>
formula.type is a linked table's int column. Thanks for the other contributions to get my resolution.
If you are having issues getting e.Item.DataItem in Bazzz's answer try
protected void ListView_ItemDataBound(object sender, ListViewItemEventArgs e)
{
using (ListViewDataItem listViewDataItem = (ListViewDataItem) e.Item)
{
if (listViewDataItem != null)
{
Label monkeyLabel = (Label)e.Item.FindControl("monkeyLabel");
bool linkable = (bool)DataBinder.Eval(listViewDataItem , "IsLinkable");
if (linkable)
monkeyLabel.Text = "monkeys!!!!!! (please be aware there will be no monkeys, this is only for humour purposes)";
}
}
}
I know it is a bit late in the day for this answer but for what it is worth here is my solution to the problem:
<%# (bool)Eval("IsLinkable") ? "monkeys!!!!!!" : "" %>
You can create a method to evaluate the value and return the value you want.
<%# IsLinkableABool( Eval("IsLinkable") ) %>
On the code behind you can create the method as follow
protected String IsLinkableABool(String isLinkable)
{
if (isLinkable == Boolean.TrueString)
{
return "monkeys!!!!!! (please be aware...";
}
else
{
return String.Empty;
}
}
Whenever I've needed to handle conditions within a databound control, I use the OnItemDataBound event.
So you could do:
protected void DataBound_ItemDataBoundEvent() {
bool IsLinkable = (bool)DataBinder.Eval(e.Item.DataItem, "IsLinkable");
if(IsLinkable) {
//do stuff
}
}
We would need to see the rest of your code, but the error message is giving me a bit of a hint. You can ONLY use Eval when you are inside of a data-bound control. SOmething such as a repeater, datagrid, etc.
If you are outside of a data bound control, you could load the value into a variable on the code-behind and make it public. Then you could use it on the ASPX for conditional processing.
For FormView Control refer to this link.
Here is the sample code. My aspx page FormView Control look like below:
<asp:FormView ID="fv" runat="server" Height="16px" Width="832px"
CellPadding="4" ForeColor="#333333" ondatabound="fv_DataBound">
<ItemTemplate>
<table>
<tr>
<td align="left" colspan="2" style="color:Blue;">
<asp:Label ID="lblPYN" runat="server" Text='<%# Eval("PreviousDegreeYN") %>'></asp:Label>
</td>
</tr>
</table>
</ItemTemplate>
</asp:FormView>
I am checking the value for <%# eval("PreviousDegreeYN") %>
If my eval("PreviousDegreeYN") == True, I want to display Yes in my label "lblPYN"
protected void fv_DataBound(object sender, EventArgs e)
{
FormViewRow row = fv.Row;
//Declaring Variable lblPYN
Label lblPYN;
lblPYN = (Label)row.FindControl("lblPYN");
if (lblPYN.Text == "True")
{
lblPYN.ForeColor = Color.Blue;
lblPYN.Text = "Yes";
}
else
{
lblPYN.ForeColor = Color.Blue;
lblPYN.Text = "No";
}
}
Putting condition aspx page is not a good idea.also messy.
U can do using ternary operator.But I suggest u to use rowdatabound events of grid view.
step 1-go to grid view properties.Click on lighting button to list all event.
Step 2-give a name on rowdatabound and double click
protected void onrow(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
TableCell statusCell = e.Row.Cells[8];//Means column 9
if (statusCell.Text == "0")
{
statusCell.Text = "No Doc uploaded";
}
else if (statusCell.Text == "1")
{
statusCell.Text = "Pending";
}
else if (statusCell.Text == "2")
{
statusCell.Text = "Verified";
}
}
}

Getting total for a column in ListView

I need to get a sum for all items in a column within a listview. I put in the following code in the itemdatabound event, but realized after testing it that it will only be getting what is bound, oops.
So I was looking for a little help converting this to show a total for my column from all items bound to the ListView.
Thanks.
if (e.Item.ItemType == ListViewItemType.DataItem)
{
ListViewDataItem item = (ListViewDataItem)e.Item;
Label lblQty = (Label)e.Item.FindControl("lblQuantity");
if (lblQty == null)
{
return;
}
if (lblQty.Text.Length == 0 || lblQty.Text == "")
{
return;
}
else
{
ListViewTotal += int.Parse(lblQty.Text);
}
}
The best method I have found to do this is to implement the OnDataBinding method for the control you are binding. For example:
<asp:ListView ID="ListView1" runat="server">
<ItemTemplate>
<asp:Literal ID="yourLiteral" runat="server"
OnDataBinding="yourLiteral_DataBinding"></asp:Literal>
</ItemTemplate>
</asp:ListView>
First define a global counter in your .cs:
private int _quantityTotal = 0;
Then implement the OnDataBinding for the control:
protected void yourLiteral_DataBinding(object sender, System.EventArgs e)
{
// You could get anything here to get a value including calling a DB
// call if you want for each item that is being bound.
Literal lt = (Literal)(sender);
int quantity = (int)(Eval("yourQuantityField"));
_quantityTotal += quantity;
lt.Text = quantity.ToString();
}
Now you have the total stored in _quantityTotal which you can then add to a footer or something else after the databinding has occurred like the OnDataBound event.
Yes, you will have to query the DB to get this value, or depending on what you are binding, loop through the collection you are binding and sum the values from the classes or DataSet/DataTable you are binding to it.
HTH.

Categories