Handling a DropDownList in a Nested ListView - asp.net

I have two nested .net ListViews. I need to filter the contents of the inner listview by selecting from a dropdown list in the outer listview. The layout of the control is like this:
<asp:listview id="lvOuter" runat="server" onitemdatabound="lvOuter_OnItemDataBound"
onitemcommand="lvOuter_OnItemCommand" onitemcreated="lvOuter_ItemCreated" onselectedindexchanged="lvOuter_SelectedIndexChanged">
<layouttemplate>
<ul>
<asp:placeholder id="itemPlaceholder" runat="server" />
</ul>
</layouttemplate>
<itemtemplate>
<asp:dropdownlist id="ddlTest" runat="server" onselectedindexchanged="ddlTerm_SelectedIndexChanged" autopostback="true" >
<asp:listitem text="6" value="6"/>
<asp:listitem text="9" value="9"/>
</asp:dropdownlist>
<asp:listview id="lvInner" runat="server" onselectedindexchanging="lvInner_SelectedIndexChanging"
onitemdatabound="lvInner_ItemDataBound" onitemcommand="lvInner_OnItemCommand">
<layouttemplate>
<asp:placeholder id="itemPlaceholder" runat="server" />
</layouttemplate>
<itemtemplate>
<!--Results displayed here-->
</itemtemplate>
</asp:listview>
</itemtemplate>
</asp:listview>
On the page load I bind data to the outer listview and on OnItemDataBound I bind the inner listview. This is all working fine, but what I need to do now is to re-bind the inner listview with a new query that includes the parameter from the drop down list. This should happen when the user selects a new value in the drop downlist. (OnSelectedIndexChanged) I can access the value easily enough through the sender, as so:
protected void ddlMyDropDown_OnSelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddlMyDropDown = sender as DropDownList;
string value = ddlMyDropDown.SelectedValue;
}
but I'm unable to then find the inner listview relating to that dropdown in order to bind the results of the new query with the added where clause. I'm sure this must be a pretty common requirement. Any pointers would be greatly appreciated.

Have you tried using something like <%# Eval("value", "{0}") %> as seen here
I seem to recall doing something akin to yours with this. It has been awhile since I have done this so sorry if this is not accurate.

Related

Binding ListView Field to Value in Code-Behind

I'm displaying fields from a DB call in a ListView. I had to re-code my database query because of an issue with repeating groups. I also didn't want to have to deal with nested ListViews. So now I am trying to set the header to the value of radio button list selection. I was trying to write a custom method to return that value but could not remember the syntax.
How can I set the header in the LayoutTemplate from the code-behind so that it doesn't repeat?
<LayoutTemplate>
<div class="resultsGrid">
<strong><%# GetHeader() %></strong>
<asp:PlaceHolder runat="server" ID="resultsPlaceHolder">
</asp:PlaceHolder>
</div>
</LayoutTemplate>
<ItemTemplate>
// rest of data
</ItemTemplate>
I was able to solve this as follows:
<asp:ListView ID="resultsList" ItemPlaceholderID="resultsPlaceHolder"
OnItemCreated="ResultsList_ItemCreated" runat="server">
<LayoutTemplate>
<div class="resultsGrid">
<strong><asp:Label ID="headerLabel" runat="server"></asp:Label></strong>
<asp:PlaceHolder runat="server" ID="resultsPlaceHolder">
</asp:PlaceHolder>
</div>
</LayoutTemplate>
<ItemTemplate>
// rest of data
</ItemTemplate>
</asp:ListView>
And in the code-behind:
protected void ResultsList_ItemCreated(object sender, ListViewItemEventArgs e)
{
if (e.Item is ListViewItem)
{
Label tempLabel = resultsList.FindControl("headerLabel") as Label;
tempLabel.Text = ViewState["ParkName"].ToString();
}
}

Passing CommandArguement to LinkButton from variable

I have seen many resources on SO that say that I can use following syntax to pass value to CommandArguement of `LinkButton'
<%forearch(var comment in Comments){%>
<asp:LinkButton ID="del" CommandArguement='<%= comment.CommentId%>' onCommand="delete_click" Text="Delete"/>
<%}%>
But when I write this in my ascx file and click on the link the value passed to command argument is "<%=comment.CommentId%>" instead of commentId itself. Please guide what am I doing wrong?
Edit 1
based on answers and comments, I have moved to use repeater instead of foreach and plain code. Here is the code I have come up with
<asp:Repeater ID="commRepeater" SelectMethod="GetPageComments" runat="server">
<ItemTemplate>
<p>
<%#Eval("Comment") %>
<%if(Page.User.Identity.IsAuthenticated && Page.User.Identity.GetUserId() == Eval("UserId")){ %>
<span>
<asp:LinkButton Text="Edit" runat="server" ID="EditLink" CommandArgument='<%#Eval("CommentId")%>' OnClick="Update_Comment" />
<asp:LinkButton Text="Delete" runat="server" ID="DeleteLink" CommandArgument='<%#Eval("CommentId")%>' OnClientClick="if (!confirm('Are you sure you want delete?')) return false;" OnCommand="Delete_Comment" />
</span>
<%} %>
</p>
</ItemTemplate> </asp:Repeater>
you can see that I am trying to show the edit and delete links if user is logged in and his Id matches with user who commented but it tells me that I can on use Eval in databound controls. how would I hide/show edit/delete links conditionally within repeater
You could simply use codebehind, for example in Page_Load:
protected void Page_Load(Object sender, EventArgs e)
{
if(!IsPostBack)
{
del.CommandArgument = comment.CommentId;
}
}
Maybe a better approach would be to use the Comments-collection(which seems to be a list or array of a custom class) as DataSource of a Repeater(or other web-databound control). Then you can add the LinkButtons to the Itemtemplate.
You can then either use ItemCreated or ItemDataBound events of the repeater in codebehind or inline ASP.NET tags to bind the CommandArgument.
For example:
CommandArguement='<%# DataBinder.Eval( Container.DataItem, "CommentId" ) %>'
What you are doing currently is not recommended and is highly error prone. You can easily achieve this with ASP.NET Repeater control like this:-
<asp:Repeater ID="MyRepeater" runat="server">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Eval("CommentId") %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
In Page_Load simply bind it:-
if (!Page.IsPostBack)
{
MyRepeater.DataSource = CommentsRepository();
MyRepeater.DataBind();
}
Or Else if you are have ASP.NET 4.5 then use strongly type Data Bound controls like this:-
<asp:Repeater ID="MyRepeater" runat="server" ItemType="MyNamespace.Comment"
SelectMethod="MyRepeater_GetData">
<ItemTemplate>
<asp:LinkButton ID="del" CommandArguement='<%# Item.CommentId %>'
OnCommand="del_Command" Text="Delete" runat="server" />
</ItemTemplate>
</asp:Repeater>
And you method in code behind should be something like this(just for Demo):-
public IEnumerable<MyNamespace.Comment> MyRepeater_GetData()
{
return new List<Comment>
{
new Comment { CommentId =1, Name= "foo"},
new Comment { CommentId =2, Name= "bar"},
};
}

DataValueField pass value to repeater?

So if the user selects a value from a dropDownList and clicks the button, the ID is passed to the code behind(which is where I want it)
E.g.
<asp:DropDownList ID="DropDownList" runat="server" AppendDataBoundItems="true" DataTextField="Company_Name" DataValueField="id">
<asp:ListItem Text="---Select---" Value="0" />
</asp:DropDownList>
So dataValueField will pass the 'id' of the selected record in the DD.
However On the same page I am using a repeater to display records that have been previously chosen from the drop down, Beside each record i have a 'Change Prices' button which I want to perform a task when clicked, all works fine however all I need is the same 'id'.
So is this done in a similar way? E.g
<asp:Repeater ID="repeaterShowName" runat="server">
<HeaderTemplate>
<tr>
<th>
<asp:Label ID="SubConName" Text="Current SubContractors" runat="server"></asp:Label>
</th>
</tr>
</HeaderTemplate>
<ItemTemplate>
<tr>
<td>
<asp:Label ID="SubCon" Text='<%# Bind ("Company_Name") %>' runat="server"></asp:Label>
</td>
<td>
<asp:LinkButton ID="AddNewBOQLink" runat="server" OnClick="EditPricesForSubContractor" CssClass="bottomhyperlink">Change Prices</asp:LinkButton>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
//So Do I add in DataValueField="id" inside the link button, so when the user selects the hyperlink beside the name, it will automatically have the 'id?
You should use the CommandArgument property of the LinkButton to pass the id to the method that handles the click.
So your LinkButton will now look like this:
<asp:LinkButton ID="AddNewBOQLink" runat="server" CommandArgument='<%# Bind("id")%>' CssClass="bottomhyperlink">Change Prices</asp:LinkButton>
And you want to add the following property to your Repeater:
<asp:Repeater .... OnItemCommand="repeater_Command" ...
The method that will handle the command event will look like this
void repeater_Command(Object Sender, RepeaterCommandEventArgs e) {
//retrieve the id like so
int id = (int)e.CommandArgument;
}
Also, note that I removed the OnClick property from the LinkButton. It is not needed as you are handling the click via the repeater's OnItemCommand method.
In addition, you may want to consider adding a CommandName propery to the LinkButton. This is used to identify which command you wish to execute. Currently, you only have a single command: Change Prices. But in the future you may want to add an additional button with a different command.
In order to do this, add the following property to the LinkButton:
<asp:LinkButton ... CommandName="ChangePrice" ...
And modify the repeater_Command method to handle the CommandName. Like so:
void repeater_Command(Object Sender, RepeaterCommandEventArgs e) {
switch(e.CommandName)
{
case "ChangePrice":
//retrieve the id like so
int id = (int)e.CommandArgument;
break;
}
}

Update on GridView combobox not updating

I am trying to bind the DropDownList(DDL) with my entity datasource. The GridView(GV) is bound to a different EntityDataSource than the DDL. The GV's EntityDataSource has a navigation property 'Bag' for the relationship. In edit mode I can pick a different item, but it does not update the database for that record. I did use the include for the navigations in the EntityDataSource. I am sure the wiring is not correct. I have tried searching with no luck so far. Thanks for the help.
<asp:TemplateField HeaderText="Bag">
<ItemTemplate >
<asp:Label ID="lbEditBag" Text='<%#Eval("Bag.Item1") %>' runat="server" />
</ItemTemplate>
<EditItemTemplate >
<asp:DropDownList runat="server" ID="ddlBags" DataSourceID="edsBags" DataTextField="Amount" DataValueField="BagId" />
</EditItemTemplate>
</asp:TemplateField>
DonA, if you've not found your answer yet I will explain what I have done to do something similar to what your after I believe.
In a gridview I have various asp:TempleteField's, one which is like this:-
<ItemTemplate>
<asp:Label ID="lblActive" runat="server" Text='<%# Bind("Active") %>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<%--<asp:TextBox ID="txtboxActive" runat="server" Text='<%# Bind("Active") %>' Width="20px" TextMode="SingleLine" CssClass="textboxEdit"></asp:TextBox>--%>
<asp:DropDownList ID="activeDDL" CausesValidation="False" AutoPostBack="False" runat="server"> <asp:ListItem Text="No" Value="0"></asp:ListItem>
<asp:ListItem Text="Yes" Value="1" Selected="True"></asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
which as you can see has two dropdownlist items in the EditItemTemplete (I also left in similar code to yours that I used to use to bind to a database for the DDL values but I don't use anymore so is commented out)
then alongside the ID, runat="server", DataKeyNames, etc. in
<asp:Gridview ID=""...
i have
OnRowUpdated="info_GridView_RowUpdated"
This then runs in my C# code behind an SQL function to update the database table with the setting from the DDL, like so (I have also put in a few other Gridview.Databind() to reset my other gridviews)
protected void info_GridView_RowUpdated(object sender, GridViewUpdatedEventArgs e)
{
// The update operation was successful. Retrieve the row being edited.
int index = info_GridView.EditIndex;
GridViewRow row = info_GridView.Rows[index];
int itemID = Convert.ToInt32(row.Cells[4].Text); // Cells[4] is only one available as others are being edited!
// update Active value in the database //
comm = new SqlCommand("UPDATE Products SET Active=#active WHERE ItemID=#itemID", objConn);
comm.Parameters.AddWithValue("#active", ddlValue); // this stores DDL value in database
comm.Parameters.AddWithValue("#itemID", itemID);// Convert.ToInt32(propertyRefTextBox.Text));
objConn.Open();
comm.ExecuteNonQuery();
objConn.Close();
// force update and reset selectedIndex of other gridviews //
Category_GridView.DataBind();
editImages_GridView.DataBind();
Category_GridView.SelectedIndex = -1;
editImages_GridView.SelectedIndex = -1;
}
hope the above helps.
Trev.

ASP.NET TreeView, select NodeTemplate upon databinding similar to the TemplateSelector in WPF?

Usage scenario,
I have hierarchically categorized items and I would like to present them in a TreeView. The TreeView will be populated on demand and it contains both the categories and the items, I would like to have different templates for the categories and the items. That is not a problem if the items were static I could easily list them in the aspx markup and specify template for each node, but on demand populating I have no clue how to do it. I don't mind any solution suggesting usage of Telerik TreeView or DevExpress Treeview.
Thanks in advanced.
Ok,
one day and no comment :), I got it done using RadTreeView, the RadTreeNode supports custom attributes, I added a custom attribute to distinguish between a category and an item, and in the NodeTemplate I used MultiView control which chooses the View to display by checking the node custom attribute.
Here is some parts of the code,
<telerik:RadTreeView ID="rtvQueries" runat="server" OnNodeExpand="rtvQueries_NodeExpand"
Skin="Black" OnClientNodeClicking="CheckNodeType" OnNodeClick="rtvQueries_NodeClick">
<NodeTemplate>
<asp:HiddenField ID="hfId" runat="server" Value='<%# Container.Value %>' />
<asp:MultiView ID="mvAll" runat="server" ActiveViewIndex='<%# Container.Attributes["ItemType"] == "C"? 0 : 1 %>'>
<asp:View ID="vwCategory" runat="server">
<asp:Label ID="lblCategory" runat="server" Text='<%# Container.Text %>' />
</asp:View>
<asp:View ID="vwQuery" runat="server">
<div style="float: left">
<asp:Label ID="lblQuery" runat="server" Text='<%# Container.Text %>' />
</div>
<div style="float: left; margin-left: 20px; overflow: hidden; width: 200px;">
<asp:Label ID="lblCommandText" runat="server" Text='<%# Container.Attributes["CommandText"] %>' />
</div>
</asp:View>
</asp:MultiView>
</NodeTemplate>
</telerik:RadTreeView>
The code-behind for NodeExpand,
protected void rtvQueries_NodeExpand(object sender, RadTreeNodeEventArgs e)
{
Guid categoryId = new Guid(e.Node.Value);
List<Category> cats = DBHelper.GetQueryCategories(categoryId);
cats.ForEach(c =>
{
RadTreeNode n = new RadTreeNode(c.Name, c.Id.ToString());
n.ExpandMode = TreeNodeExpandMode.ServerSideCallBack;
n.Attributes["ItemType"] = "C";
e.Node.Nodes.Add(n);
n.DataBind();
});
List<RightBI.Query> queries = DBHelper.GetQueriesByCategoryId(categoryId);
queries.ForEach(q =>
{
RadTreeNode n = new RadTreeNode(q.Name, q.Id.ToString());
n.Attributes["ItemType"] = "Q";
n.Attributes["CommandText"] = q.CommandText;
e.Node.Nodes.Add(n);
n.DataBind();
});
}
The only problem in this solution is I have to call DataBind on each node after adding it to the TreeView so the binding expressions evaluated.
I still would like to see other solutions and comments on this solution or better ideas.

Resources