eval in if statement? - c#

<% if(Eval("SaveDate") != DBNull.Value){ %>
do magic
<%} %>
gives me error: Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.
I could write : <%# Eval("SaveDate") != DBNull.Value ? do magic
But I need to do lots of html magic in if statement.
I know I should add # in order to use Eval, but not sure about correct syntax.

One solution is to wrap the content in a runat="server" tag with a Visible value, e.g.,
<div runat="server" Visible='<%# Eval("SaveDate") != DBNull.Value %>'>
do magic
</div>
div can be any HTML tag, but <asp:Panel> and <asp:PlaceHolder> could also be used. Note that "do magic" is still databound, so it's not a perfect solution if it contains expensive code or code that could generate an error if Eval("SaveDate") == DBNull.Value.
Note that Visible="false" will omit the tag and all its contents from the generated HTML, this means that it is very different from style="display:none" or style="visible:hidden", so don't worry about that.
But, if your "do magic" is reasonably complex, another rather simple solution (a bit of a hack) is: use a Repeater (or FormView) with its DataSource set to an array of one item (visible) or no items (hidden):
<asp:Repeater runat="server" DataSource='<%# ElementIfTrue(Eval("SaveDate") != DBNull.Value) %>'
<ItemTemplate>
do magic
</ItemTemplate>
</asp:Repeater>
protected IEnumerable ElementIfTrue(bool condition)
{
if (condition)
return new object[] { Page.GetDataItem() };
else
return new object[0];
}
The actual contents of the datasource array is either empty (hidden) or the element you were already binding to. This makes sure you can still call <%# Eval(...) %> inside the ItemTemplate.
With this approach, your "do magic" is a template which will only be executed if DataSource has one or more items. Which is taken care of by ElementIfTrue. It's a bit of a mind bender, but it can save you every once in a while.
As a side note: packing your "do magic" in a user control can also keep the complexity down. You don't really need to change a thing in your HTML/ASP.NET tag mix (<%# Eval("...") %> still works even inside a user control).

I usually add a protected function returning a string to the code-behind to generate the content:
On the page:
<%# Eval("SaveDate") != DBNull.Value ? GenerateContent() : string.Empty %>
In my class:
protected string GenerateContent()
{
return "Hello, World!"
}

Related

ASP.Net Repeater Eval in an If statement

So I've been looking around for a good answer to this question, but haven't really found anything useful. Hopefully someone can shed some light on this for me.
Basically, I have a repeater that is backed by a database table. Inside the ItemTemplate for this repeater, I have some HTML elements that are populated with properties from each item in the list. Pretty standard stuff. However, there is a possibility that one of the items could be null. In that case, it would make sense for me to put some sort of if (blah != null) logic around the offending code. The only problem is, when I've tried to do so, ASP throws up on me, telling me that I can't use an if statement inside of <%# %>.
My question to the masses is this: if you can't use an if statement inside of <%# %>, then how are you supposed to do conditional logic based on the values of each item?
I know that you can call your own methods inside the repeater, but that won't work for what I'm trying to do.
Below is what I'm trying to accomplish, to better illustrate my point.
<asp:Repeater runat="server" ID="repeater">
<ItemTemplate>
<div class="item-wrap">
<% if(Eval("imageUrl") != null) { %>
<div class="plan-img">
<asp:Image runat="server" ImageUrl='<%# Eval("imageUrl") %>'/>
</div>
<% } %>
</div>
</ItemTemplate>
</asp:Repeater>
inside your ItemTemplate write the markup like this:
<asp:Panel runat="server" Visible='<%# Eval("imageUrl") != null %>'>
<asp:Image runat="server" ImageUrl='<%# Eval("imageUrl") %>'/>
</asp:Panel>
Basically you can't mix code <% with databinding constructs <%#.
My advice would be to add the following property in your CodeBehind:
protected YourClass DataItem
{
get
{
return (YourClass)this.Page.GetDataItem();
}
}
and then write the markup without Eval():
<asp:Image runat="server" ImageUrl='<%# DataItem.imageUrl %>'/>
You're supposed to generate the same content for every item in the template. If you don't need to use it for a particular item just set it's visibility to false in the binding events.

Calling function in usercontrol inline code doesn't always work

I have constructed an ASP.NET user control "Box.ascx" wtih the following code.
<div id="divContent" runat="server" visible='<%# AllowedToView(this.Privacy) %>'>
Content
</div>
In the codebehind, "Box.ascx.cs" has the following code.
public string Privacy = string.Empty;
public bool AllowedToView(string privacy)
{
return true;
}
When I use this control in a repeater, AllowedToView() function is hit. If I use this control without a repeater, AllowedToView() function isn't called. I want to know why this weird situation happens and how can I make the control call the AllowedToView() function when used without repeater.
Details are below.
I use this control in a repeater in "Default.aspx".
<asp:Repeater ID="rpRecords" runat="server">
<ItemTemplate>
<uc1:Box ID="myBox" runat="server" RecordID = '<%# Eval("RecordID") %>' />
</ItemTemplate>
</asp:Repeater>
The repeater is databound in "Default.aspx.cs" with the following code:
DataTable dt = FillTable();
rpRecords.DataSource = dt;
rpRecords.DataBind();
I use the "Box.ascx" control in "ShowBox.aspx" with the following code.
<body>
<uc1:Box ID="myBox" runat="server" />
</body>
I give values to the user control from the codebehind with the following code.
protected void Page_Load(object sender, EventArgs e)
{
myBox.RecordID = "1";
}
As mentioned in another answer, the # means it will require databinding to be executed.
So to answer your question "How to make it run outside of the repeater" the simple answer is to call myBox.DataBind().
Your question is very similar to asp.net inline code <%# MyboolVal %>. The problem is that <%= is equal to Response.Write and outputs straight HTML, so it won't work when setting the visible property.
I don't think you need the # but instead = in the ASP tag. Pretty sure # is only for databinding events and that's why it works in a repeater because a repeater performs a databound for rendering.
Check this link: http://blogs.msdn.com/b/dancre/archive/2007/02/13/the-difference-between-lt-and-lt-in-asp-net.aspx
Im no expert on webforms but i think that your problem is that you are trying to databind that method and thats not working for you, try putting it in a <%= AllowedToView(this.Privacy) %>

Passing in a value to a usercontrol through a foreach loop

in my asp.net mark up I have a foreach loop that iterates through a simple list. In this foreach loop I am adding a new user control and attempting to pass in the value from the loop. However, this value just wont budge and get inside that damn control! Anyone have any suggestions?
<%foreach (userInfo i in this.items)
{ %>
<uc1:ItemControl ID="ItemControl" runat="server" UserID='<%#Eval("userID") %>'/>
<%} %>
userID is a public property in the control, when it goes to set, the value is just literally : <%#Eval("userID") %>. I've tried #Bind and =Value but nothing seems to work.
Any help would be appreciated!
Looks like the perfect use case for a repeater:
<asp:Repeater runat="server" id="myRepeater">
<uc1:ItemControl ID="ItemControl" runat="server" />
</asp:Repeater>
You can databind your list (this.items) to the repeater and in the code behind, in the DataBind event set the UserID property of the ItemControl control.
The reason your approach will not work is that IDs have to be unique in a page.
Try use a Repeater control for your purpose

Asp.net grdiview: can i format the dataitems in an itemtemplate?

i have this code in an itemtemplate in a gridview:
<%# DataBinder.Eval (Container.DataItem, "DiscountAmount")%>
It's a decimal value, and it shows 20.300000000000, which is technically right, but i'd prefer to show 20.30 or 20,30, depending on the culture.
But i've never been a big fan of gridviews, and the DataBinder.Eval and Container.DataItem haven't been good friends either, and i'm lost with how to use it.
it has a special prefix (<%#) and when i type anything other then the original code it's no good, but changing <%# to <%= or <% doesn't seem to work either?
This will also work:
<%#= String.Format("{0, 0:N2}",DataBinder.Eval (Container.DataItem, "DiscountAmount"))%>
Edit: I share your discomfort with declarative databinding syntax. You can accomplish the same thing in code-behind by calling the RowDataBound event and implementing whatever changes you want to make as the data is bound to the GridViewRow.
To do this, you need to wire up the event in the markup by setting OnRowDataBound to the name of your event handler, something like this:
<asp:GridView ID="InvoiceGrid" OnRowDataBound="InvoiceGrid_RowDataBound".....>
Then you create an event handler in code behind with a signature like this:
protected void InvoiceGrid_RowDataBound(object sender, GridViewRowEventArgs e)
The first thing you do in that event handler is test which type of GridViewRow type it is:
if (e.Row.RowType == DataControlRowType.DataRow)....
Then you do whatever formatting you want to do.
For folks happy with declarative markup, this may seem burdensome. But for people who are comfortable writing code, you can do a whole lot more here in code behind.
Did you try this?
<%= String.Format("{0:0,0.00}", DataBinder.Eval (Container.DataItem, "DiscountAmount"))%>
or just
<%# DataBinder.Eval(Container.DataItem, "DiscountAmount", "{0:0,0.00}")
You can read more format options in the article String Format for Double.
There are several ways...some of them stated above and here is another one:
Text='<%# GetFormattedDiscount(Eval("DiscountAmount").ToString())%>'
GetFormattedDiscout is a function in your code-behind where you can do whatever formatting you need and return it as string:
protected void GetFormattedDiscount(string amount){
return String.Format("{0:N2}",amount);
}
Even this should work:
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%#String.Format("{0:n2}",Eval("DiscountAmount")) %>'></asp:Label>
</ItemTemplate>

Binding the DataSource of a repeater

I am using databinding to iterate through a recordset returned from the database, and one of those recordsets is a comma separated list of items - I'm trying to use a second repeater to display each of those items as a hyperlink. So far this is the code that I have:
<asp:Repeater ID="myRepeater" runat="server" DataSource='<%# DataBinder.Eval(Container.DataItem, "SomeList").ToString().Trim(',') %>'>
<ItemTemplate>
<a href='http://somesite/downloadattachment.aspx?itemid=<%# Container.ItemIndex %>'><%# Container.DataItem %></a>
</ItemTemplate>
</asp:Repeater>
The trouble is that so far there are 3 reasons why this doesnt work:
I get a server tag is not well formed error unless I remove the runat="server" - why is this? (And why does it work without the runat="server"?)
Container.DataItem Evaluates to an instance of System.Data.DataRowView - how do I get the current piece of the string that I split?
More importantly, this only seems to print out 1 Container.DataItem, even when I know there is a comma in the string I've given it - any ideas?
Instead of Eval(), for non-trivial scenarios I generally cast Container.DataItem to the type I want, and then act on it from there in a type-safe way.
The "not well formed" error is caused by the single-quotes around the parameter to Trim(). If you use single quotes on the outside of your attribute definition, you can't use them inside it. In cases like yours where a databinding definition has a lot of code in it, I often create a helper method (either inside a script runat=server for for MVC views and other inline-code-friendly cases, or in code-behind for traditional web forms apps) which handles the code I want to run. By refactoring into a method, it clarifies the HTML and sidesteps the lame single/double-quote restrictions.
Regardless of where you put the code, In your case, you want to:
cast Container.DataItem to DataRowView
extract the SomeList column value using the [] operator
call String.Split() on that string to turn your CSV string it into an array of strings
use that as a data source of your inner repeater
The code should look something like this:
<asp:Repeater ID="myRepeater" runat="server"
DataSource='<%# ((System.Data.DataRowView)Container.DataItem)["SomeList"].ToString().Split(new string[] {","}, StringSplitOptions.RemoveEmptyEntries)%>'>
<ItemTemplate>
<a href='http://somesite/downloadattachment.aspx?itemid=<%# Container.ItemIndex %>'>
<%# Container.DataItem %>
</a>
</ItemTemplate>
</asp:Repeater>
Did you specify the updatecommand, deletecommand to the sqldatasource?
Even if the proper parameters haven't been supplied, the affected rows will always be 0. If it has two parameters for the update command, two parameters have to be supplied through updatecommand.
For more information on this please check this URL: http://www.itpian.com/Coding/4774-Data-binding.aspx

Categories