How to hide a column in a repeater? - c#

Here, I found once the code to hide a repeater column easily. It works great like this.
<ItemTemplate>
<tr>
<td><asp:Label runat="server" ID="label1" /></td>
<% if (MustBeVisible) { %>
<td"><asp:Label runat="server" ID="label2" /></td>
<% } %>
</tr>
</ItemTemplate>
But now, I need to apply a CLASS to the TableRow and make it runat="server" in order to apply a color condition in the ItemDataBound but when I add the attribute of runat="server" I have a conflict at runtime and a warning.
ASP.NET runtime error: Code blocks are not supported in this context
The idea is, for example, to evaluate in the ItemDataBound the label1, if it's true must apply a Class on TR to make it grey.
Any idea of the best approach or how to resolve this?

Approach 1:
First, Define a bool property, say ShouldBeGreyed in your data-item class (if possible). This property should return whether the data-item will be greyed out or not.
Then, Use this in your repeater markup:
<ItemTemplate>
<tr<%# ((bool)Eval("ShouldBeGreyed"))?"class='grey'":"" %>>
...
</ItemTemplate>
Approach 2:
First, define a method in code-behind, say ShouldBeGreyed, like this:
protected bool ShouldBeGreyed(object item)
{
// cast to your data-item
var dataItem = (<class-of-your-data-item>)item;
// Determine if it should be greyed out
// bool shouldBeGreyed = ...
...
return shouldBeGreyed;
}
Now use this in your repeater markup:
<ItemTemplate>
<tr<%# ((bool)ShouldBeGreyed(Container.DataItem))?"class='grey'":"" %>>
...
</ItemTemplate>

Use something like this.. Write the method in the Visible portion of the label.
<td><asp:Label runat="server" ID="label2" Visible="<%# MustBeVisible() %>" /></td>
if you want the td to be invisible/visible use this
<td runat="server visible="<%# MustBeVisible() %>"><asp:Label runat="server" ID="label2" /></td>

If you made the <td id="tablerow" runat="server"/> could you use do something like:
tablerow.Attributes.Add("class", className);

Related

How does Eval resolve to DataBinder.Eval?

I'm trying to understand how the Eval() statement in ASPX/ASCX resolves to the DataBinder.Eval(context, expression) method, and more so where Eval("Value") goes to do it's Reflection before reaching this method?
I'm considering a couple of things that I'd like to do:
Introduce a similar thing to Eval - say EvalList() which justs dumps all the avaliable fields via Reflection that can be bound to, just to help when debugging/developing to determine what's avaliable on the context. I'd like to be able to just type EvalList() rather than SomeHelper.EvalList()
Re-direct Eval("") to a different method, which will Debug.Assert() or similar to warn the developer if it's being over-used and that something else might be better for performance.
Avoid Eval() all together and use the model binding feature in ASP.NET WebForms 4.5 and later, like this:
Pre-ASP.NET 4.5 way using Eval():
<asp:ListView ID="OrdersListView" runat="server">
<ItemTemplate>
<tr>
<td>
<asp:Button ID="EditButton" runat="server" Text="Edit"
CommandName="Edit" />
</td>
<td>
<asp:Label ID="OrderID" runat="server"
Text='<%# Eval("SalesOrderID") %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
Model binding way:
<asp:ListView ID="OrdersListView" runat="server"
ItemType="YourNamespace.YourClass">
<ItemTemplate>
<tr>
<td>
<asp:Button ID="EditButton" runat="server" Text="Edit"
CommandName="Edit" />
</td>
<td>
<asp:Label ID="OrderID" runat="server"
Text='<%#: Item.YourPropertyName %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
Note: Because ItemType is strongly typed you will get IntelliSense help in Visual Studio as you type Item..
Read ASP.NET 4.5 Web Forms Features - Strongly-Typed Data Controls for a quick overview of how you may never need Eval() again.

Binding single value to aspx page

Trying to bind a value in code behind to aspx page.
<div>
<table>
<tr>
<th>Item</th>
</tr>
<tr>
<td><asp:Label ID="Label1" runat="server" Text='<%# Eval("ItemId")%>'/></td>
</tr>
</table>
</div>
Code behind:
int ItemId = 3;
NOTE: I have tried:
<%=ItemId%> AND <%:ItemId%>
But no joy! What am I doing wrong? All I want to do is to bind to a single value.
<asp:Label ID="Label1" runat="server" Text='<%# ItemId %>'/>
This is the proper format on the page, but you also need to execute a data binding event in your codebehind:
int ItemId = 3;
this.DataBind();
Although philreed has it right that since you are already using a label, you might as well just update the label.Text property with your value, rather than go through the data binding process. Using the <%# ItemId %> is best for when you want to stick a random data value in the middle of regular page markup, not an ASP control, like so:
<div>
The number you picked is <%# ItemId %>.
</div>
It still needs the DataBind() in your codebehind when doing this.
If its only ever the single value, why not use this in your code behind?
Label1.Text = ItemId.ToString();
and remove the <%# Eval("ItemId")%> from your markup.
<asp:Label ID="Label1" runat="server" Text='<%# ItemId %>'/>

disabling clientidmode

I have a Repeater like this
<asp:Repeater runat="server" DataSourceID="HeaderFooterSqlDataSource">
<HeaderTemplate>
<table border="0" width="100%">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<input runat="server" id="SelectRadio" type="radio"
name="HeaderFooter" onclick='SelectAndSetHeaderFooter(this);" %>' />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
Now here when this Repeater is rendered the name attribute of my input radio "SelectRadio" gets auto generated but name attribute for all the radiobuttons in my repeater should be same so that they can work like a group & get checked / unchecked automatically according to other elements in that group, So how can I overcome this situation ??
Edit
I got the solution my self, Actually I have defined my input radio control as runat="server" because I thought otherwise Eval() binding wouldn't work but I was wrong Eval() binding does work without runat="server" , So when I remove that attribute name doesn't generated automatically and everything is fine now, But thanx to all for sparing time for my question.
Instead of hacking this you should use the built-in RaidoButtonList control.
<asp:RadioButtonList id="RadioButtonList1" runat="server">
<asp:ListItem>Item 1</asp:ListItem>
<asp:ListItem>Item 2</asp:ListItem>
<asp:ListItem>Item 3</asp:ListItem>
<asp:ListItem>Item 4</asp:ListItem>
<asp:ListItem>Item 5</asp:ListItem>
<asp:ListItem>Item 6</asp:ListItem>
</asp:RadioButtonList>
You want to look into the asp:RadioButton control (http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.radiobutton.aspx).
In particular the GroupName property on this control can be used to "specify a grouping of radio buttons to create a mutually exclusive set of controls"
So roughly speaking:
<asp:RadioButton runat="server" id="SelectRadio"
GroupName="HeaderFooter" %>' />
Edit: It seems that in this particular situation GroupName doesn't do what it is designed for. http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.radiobutton.groupname.aspx discusses it in the community content at the end but it boils down to the fact that it uses its current NamingContainer still as part of its name rather than just using the groupname you have given it. Thanks to the mysterious user1429080 for bringing that to my attention in comments.
The reason your radio buttons are not acting as a group is because you have runat="server" which will cause the name and id attributes to be prepended with parents' ids. The following will cause the radio buttons to behave as a cohesive group (note the lack of runat="server"):
ascx code:
<asp:Repeater ID="uxRadioSelections" runat="server">
<HeaderTemplate>
<table border="0" width="300px">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<input type="radio" value='<%# Eval("Name") %>' name="HeaderFooter" onclick="alert(this.value);"><%# Eval("Name") %></input>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
code behind:
protected void Page_Load(object sender, EventArgs e)
{
string[] names = new string[] {"Alvin", "Simon", "Theodore"};
uxRadioSelections.DataSource = names.Select(x => new { Name = x });
uxRadioSelections.DataBind();
}
However, the following will NOT perform as a cohesive group:
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
Test
<asp:Repeater ID="uxRadioSelections" runat="server">
<HeaderTemplate>
<table border="0" width="300px">
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:RadioButton Text='<%#Eval("Name") %>' runat="server" />
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</asp:Content>
Due to the naming conventions you alluded to, these individual radio buttons will not find each other. ASP.NET uses RadioButtonLists to overcome this:
ascx code:
<asp:RadioButtonList ID="uxRadioButtons" runat="server">
</asp:RadioButtonList>
code behind:
protected void Page_Load(object sender, EventArgs e)
{
string[] names = new string[] {"Alvin", "Simon", "Theodore"};
uxRadioButtons.DataTextField = "Name";
uxRadioButtons.DataValueField = "Name";
uxRadioButtons.DataSource = names.Select(x => new { Name = x });
uxRadioButtons.DataBind();
}
This does not give you as granular control, but will provide easy server-side access to the selections. If all you need is javascript-related functionality and increased formatting flexibility, the first format may (which is nearly identical to what you provided) is your best bet. Good luck!
Another option is to set the ClientIDMode as 'static' which will set its value to that of the ID specified. Since it is a repeater control, all the items generated will thus have the same generated ID. So you simply set:
<asp:RadioButton runat="server" id="SelectRadio" GroupName="HeaderFooter" ClientIDMode="static">' />
This means that all generated controls will have the same ID specified i.e. "SelectRadio". This may or may not be problematic and you should be careful that this is exactly what you want.
Just a note, ClientIDMode is a feature of ASP.Net 4.0. More info here: ClientIDMode in ASP.NET 4.0 and here: MSDN. I hope this helps.
Update 1:
You can get more insights from this question asked before on StackOverflow. (It's jQuery though).

td style in repeater won't output bound value ("This is not a scriptlet. Will output as plain text")

I have a repeater with a table in it with lots of properties of the td's bound by the repeater.
I have had to add a runat server to each td so I can add a visible attribute, because depending on the data some tds aren't visible.
Now I have added the runat server I am having a problem setting the background colour of my tds. It is done with a bound value.
When I add my <%%> tags to my style they are output as plain text, It even says in my html that "This is not a scriptlet. Will output as plain text" where as the rest of my <%%> tags bind correctly.
Why won't my style bind anymore?
Other tags I add will, but just not style?
Here's a cut down version of my repeater.
<table id="Table1" border="1" cellpadding="0" cellspacing="0" class="groups">
<tr id="Tr1" class="thead">
<td colspan='<%#AllowedItems.Count() %>' align="center">
items
</td>
</tr>
<tr class="theadL">
<td id="Td1" runat="server" visible='<%#ItemAllowed("Item1")%>'>
item1
</td>
<td id="Td2" runat="server" visible='<%#ItemAllowed("Item2")%>'>
item2
</td>
<td id="Td3" runat="server" visible='<%#ItemAllowed("Item3")%>'>
item 3
</td>
</tr>
<asp:Repeater ID="Repeater1" runat="server" DataSource='<%# GetData((int)Eval("Id"))%>'>
<ItemTemplate>
<tr>
<td id="Td9" title='<%#Eval("Item1Status")%>' runat="server" visible='<%#ItemAllowed("Item1")%>'
style='background-color: <%#Eval("Item1StatusColour")%>;'>
</td>
<td id="Td10" title='<%#Eval("Item2Status")%>' runat="server" visible='<%#ItemAllowed("Item3")%>'
style='background-color: <%#Eval("Item3StatusColour")%>;'>
</td>
<td id="Td11" title='<%#Eval("Item3Status")%>' runat="server" visible='<%#ItemAllowed("Item4")%>'
style='background-color: <%#Eval("Item4StatusColour")%>;'>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
Update
The style renders like this :
style="background-color:<%# ""+ Eval("Item1StatusColour")%>;"
All the rest of the attribute render how they should.
Update
This is the ItemAllowed method as requested
public bool ItemAllowed(string item)
{
//allowed items is a list<string>
return AllowedItems.Contains(item);
}
The first thing I would recommend is using css classes instead of what you are doing.
When you use html elements with runat=server, you are converting it into an html control and .net is rendering the final output. Your particular issue arises from .net wrapping the value with htmlencode or something to that effect.
I would suggest perhaps using a gridview with a onrowdatabound event. Then you can do anything programmitically in the code-behind.
I don't think it likes a combination of code and inline strings, so you could try doing it all in code:
<td ... style='<%# "background-color:" + Eval("Item2StatusColour")%>'>
Unfortunately don't have VS in front of me so can't verify it, let me know if it works.
If your controls are runat server I would personally recommend hooking into the OnItemDataBound event within the repeater, and then in your code behind handle all of your calculations there. Here's a quick example
ASPX
...
<asp:Repeater ID="rptItems" runat="server" OnItemDataBound="rptItems_OnItemDataBound" DataSource='<%# GetData((int)Eval("Id"))%>'>
<ItemTemplate>
<tr>
<td id="Td9" runat="server"></td>
<td id="Td10" runat="server"></td>
<td id="Td11" runat="server"></td>
</tr>
</ItemTemplate>
</asp:Repeater>
...
Code behind
protected void rptItems_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType != ListItemType.AlternatingItem && e.Item.ItemType != ListItemType.Item)
{
return;
}
var currentItem = e.Item as YourDataItemTypeHere;
var td9 = e.Item.FindControl("Td9") as HtmlTableCell;
td9.Attributes["title"] = currentItem.Item1Status;
td9.Style["background-color"] = currentItem.Item2StatusColour;
...
}
On a side note
From a more readable perspective I would also recommend renaming controls to something more readable, i.e. what is td9, td10 and td11? Instead it would be easier to understand if it were say tdFirstStatus, tdSecondStatus and tdThirdStatus, but that's just a preference thing.
Just noticed that my answer is exactly the same as Sir Crispalot's! I have however tested this and I've replicated the bug and the fix in Visual Studio 2008...
Like this...
<td id="Td9" title='<%#Eval("Item1Status")%>'
runat="server"
visible='<%#ItemAllowed("Item2")%>'
style='<%# "background-color:" + Eval("Item2StatusColour")%>' >
I believe that Eval is expecting a dataitem name, not an expression. However <%# %> expects an expression which can contain operations. The Eval can then be used within here and concatenated to the string "background-color".
I don't fully grok all the asp inline-tags - they're always a headache!
PS - I notice there is a mismatch between the Item numbers within your <td>s - is this intentional? eg Item1 and Item2 are referenced within the same <td>...

Need help with repeater

This is my repeater:
<asp:Repeater ID="myRepeater" OnItemCommand="myRepeater_ItemCommand" runat="server" OnItemDataBound="myRepeater_OnItemDataBound">
<HeaderTemplate>
<table width="99%" border="0" cellpadding="0" cellspacing="0">
<tr class="lgrey">
<td>Default</td>
</tr>
</HeaderTemplate>
<ItemTemplate>
<table>
<tr>
<td>
<asp:LinkButton ID="lnk1" Text="Make Default" CommandName="SetDefault" runat="server" Visible="True" CommandArgument='<%#Eval("UserID") %>' CausesValidation="false"></asp:LinkButton>
<asp:Label ID="label1" Text="Yes" runat="server" Visible="False"></asp:Label>
</td>
</tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
What I want is that when user clicks on any of
the "lnk1" link button in the list that repeater renders,
the link should be replaced with the label "label1"..
i.e. when the user clicks on "Make Default" link, it should be replaced with "Yes" label
Calling this method obj.SetDefaultAddress(); is setting the default address in the DB alright..
problem is with the display of the label1 and lnk1 when the repeater renders...
what is happening is that BOTH "Make Default" LinkButton and the "YES" label are getting displayed
under the "Default" column of the table inside my repeater.
I want some code that will check the "IsDefault" value in my DB and display "Make Default " link button
and "YES" label accordingly... i.e. if IsDefault's value in the DB is TRUE then "YES" should be displayed in the repeater
otherwise "Make Default"
Are you sure your piece of code in code behind under ItemCommand is executing?
I only changed the CommandName from SetDefault to SetDefaultAddress in aspx file to match with the one in code behind, it worked.
Where to start...
I think what's causing your problem is that the SelectedItem and the DefaultAddress are not mapped to each other, so when you click the button you're getting the selected index set and the OnItemDatabound event is showing/hiding what you want, but when the grid is initialized from the database, the SelectedItem is not being set.
I don't know what your datasource is, and there's obviously more code to this than what you've posted, but if you can look at the e.Item.DataItem in the myRepeater_ItemDataBound handler, you can set the current item as selected when the address is the default (e.Item.ItemType... or use your "selectedIndex" counter)
I will probably do it from markup itself - this is assuming that you have "IsDefault" column/property of bit/boolean type in your data-source indicating the address is default. So use following markup:
...
<tr>
<td>
<asp:LinkButton ID="lnk1" Text="Make Default" CommandName="SetDefault" runat="server" Visible='<%# !Eval("IsDefault") %>' CommandArgument='<%#Eval("UserID") %>' CausesValidation="false"></asp:LinkButton>
<asp:Label ID="label1" Text="Yes" runat="server" Visible='<%# !Eval("IsDefault") %>'></asp:Label>
</td>
</tr>
...
You need to control visibility based on property in your data source (either using markup or ItemDataBound event). Also when SetDefault link is clicked, you must either re-bind the repeater new state or toggle visibility explicitly (as your current code is doing).
EDIT:
If data binding expression are not working then you have to do it in ItemDataBound event. I see that you have already tried that but there is one mistake - bllUsers obj=new bllUsers(); will always have IsDefault as false - you need to use data item. For example,
protected void myRepeater_ItemDataBound(Object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
bllUsers obj = e.Item.DataItem as bllUsers;
((Label)e.Item.FindControl("ldefault")).Visible = obj.isDefault;
((Button)e.Item.FindControl("btnMakeDefault")).Visible = ! obj.isDefault;
}
}

Categories