Passing in a value to a usercontrol through a foreach loop - c#

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

Related

Initialize a variable in the Webform template and refer it inside a repeater

I am trying to assign an Eval value to a variable and trying to use that inside a repeater. Here's a brief example of what I am trying to do:
<ItemTemplate>
<% var test= Eval("year") %>
<asp:Repeater DataSource='testlist'>
<ItemTemplate>
<a class="testclass" href='/testlink/<%= test%>/'>Test this</a>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
I end up getting this error
CS0103: The name 'test' does not exist in the current context
I think my syntax is wrong. I tried looking for options for this online but most of them suggested a variable in the code behind. I am working with Sitefinity Webform templates, so would like to avoid code behind. Is there any way to do something on the aspx page itself instead of a code behind?
One thing I forgot to mention is that the testlist does not have year property. The year property exists outside the repeater. And hence I want to assign it to a variable and use.
Use like below
<ItemTemplate>
<asp:Repeater DataSource='testlist'>
<a href='/testlink/<%#DataBinder.Eval(Container.DataItem, "test") %>'>Test this</a>
</asp:Repeater>
</ItemTemplate>

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

eval in if statement?

<% 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!"
}

Add controls dynamically to a listview

I have an asp.net listview. The data that populates it is sorted into groups, and i'm using some code in the listview item template, that essentially checks if the grouping field has changed in the data, and if so it prints a new row, with the heading, so it looks a bit like this:
<ItemTemplate>
<%# AddGroupingRowIfWPHasChanged() %>
<tr id="row" class="GridViewRow" runat="server" >
<td valign="top" align="left" ><%# Eval("item1") %></td>
.......
</itemTemplate>
This works great. However now I need to add a button the the group heading field, and I can't seem to get this to work. Obvioulsy this button only needs adding if the heading has changed, but the AddGroupingRowIfWPHasChanged() method does not seem to have access to the current ListviewItem, so I can't add a control.
Any suggestions on how I can add a control to a list view dynamically, depandant on whether its a group heading or not?
It may be easier to override the ItemInserting event in the codebehind and do it from there
Use a placeholder?
.aspx
<asp:Placeholder id="plhControlHolder" runat="server" />
code-behind
' ** use FindControl if instead a databound event, otherwise you could skip.
Dim plcControlHolder as PlaceHolder = e.Row.FindControl("plcControlHolder")
Dim btnDynamic As New Button
btnDynamic.Id = "MyButton"
plcControlHolder.Controls.Add(btnDynamic)
Try using the GroupTemplate and GroupSeparatorTemplate instead of trying to fit it all in the ItemTemplate.
Create a UserControl to include in place of the AddGroupingRowIfWPHasChanged() method call. Override Render(). Use the logic that's currently in AddGroupingRowIfWPHasChanged() to render the control if the group has changed; otherwise, render an empty string.

How to set DropDownList's selected value inside a Repeater?

I need to create a group of DropDownLists to show and allow change of a property group for an item.
I have the following code on my ASP page.
<asp:Repeater runat="server" ID="repeaterProperties">
<ItemTemplate>
<p><asp:DropDownList runat="server" ID="ddProperty" OnInit="ddProperty_OnInit" /><p>
</ItemTemplate>
</asp:Repeater>
The ddProperty_OnInit populates the DropDownList with all the possible values with a database query.
How can I set the selected value of each created DropDownList according to the Repeater's source data?
Let's say, for example, that we have the possible property values of A, B and C.
If the database output for the Repeater contains two of those values, A and B, the Repeater outputs two DropDownLists, both with all 3 values availabla and the first one with A as selected value and the second one with B as selected value.
Edit:
It seems that adding OnItemDataBound="repeater_ItemDataBound" to the Repeater and selecting the appropriate value in there is not the way to go in my case. This is because I also need to save the possibly changed values to a database.
The ItemDataBound event of the Repeater is fired before the OnClick event on a Button and changes the selected values to their old values before the new selections can be saved.
Any suggestion on how to work around this?
Current code:
<asp:Repeater runat="server" ID="repeaterJako" OnItemDataBound="repeater_ItemDataBound">
<ItemTemplate>
<asp:DropDownList id="ddJako" runat="server" OnInit="ddJako_OnInit">
</asp:DropDownList><br />
</ItemTemplate>
</asp:Repeater>
<asp:Button runat="server" id="updateButton" Text="Save" OnClick="update_OnClick" />
In the code-behind, ddJako_OnInit populates the drop down list with all the possible choises, while the repeater_ItemDataBound uses the method suggested by Bryan Parker to select the proper value.
Maybe I'm misunderstanding something about your question... but it seems like this is exactly what OnItemDataBound is for. :)
Use FindControl to get a reference to your DropDownList in the event handler. Also check to make sure the item is not the header/footer. The example from MSDN does both these things:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.repeater.onitemdatabound.aspx
In regard the problem I specified in my edit, the time of the DataBind plays an important role. I used to do the databinding in the Page_Init event, which caused the repeater_ItemDataBound event to be fired before the button_OnClick event.
The solution was to move the databinding to the Page_PreRender event.
The population of the DropDownList with all the choises is still done in its OnInit event.

Categories