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;
}
}
Related
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"},
};
}
I have a page with FormView and a plain html table inside. The table serves for layout and contains child controls data-bind to SqlDataSource. My problem is that if I add runat=server attribute to the table declaration, all controls inside the table set my SQL parameters at NULL in DataSource_Updating event and thus the record gets updated with NULLs instead of actual values. If I don't add runat=server, everything works fine. Sample of my code:
<asp:FormView ID="SettingsFormView" runat="server" DataKeyNames="Id" DataSourceID="SettingsDataSource"
DefaultMode="Edit" Width="560px">
<EditItemTemplate>
<strong>Settings</strong>
<table runat="server" width="350px">
<tr>
<td width="160">
Time (sec)
<dx:ASPxSpinEdit ID="textTime" runat="server"
Height="21px" Number="0" Value='<%# Bind("Time") %>' Width="104px" />
<br />
</td>
<td>
</td>
</tr>
</table>
</EditItemTemplate>
</asp:FormView>
I want to be able to remove (set invisible) some rows in code behind, that's why I need to set runat=server. However I can't get anywhere with this because SQL record updates with NULLs. Please, advice what might be wrong in my code.
Try using this.
<!-- toggle through OnLoad (can use ID as well) -->
<asp:PlaceHolder runat="server" OnLoad="MakeVisibleOrNot">
<tr>
...
</tr>
</asp:PlaceHolder>
and in the code behind:
protected void MakeVisibleOrNot(object sender, EventArgs e)
{
((Control) sender).Visible = ConfigUtil.DisplaySummaryComment;
}
On the DropDownList SelectedIndexChanged, the page posts back and records the name of the developer in the radiobutton. When the user clicks the Update link on the GridView, I want the customValidator to check if the Radiobutton is empty.
<EditItemTemplate>
<table>
<tr>
<td>
<asp:DropDownList ID="_ddlAllDev" runat="server" AutoPostBack = "true" DataTextField = "Text"
DataValueField = "Value" OnSelectedIndexChanged = "ddlAllDev_SelectedIndexChanged">
</asp:DropDownList>
</td>
</tr>
<tr>
<td>
<asp:RadioButtonList ID="_rblAllDev" runat="server" AutoPostBack = "true" DataTextField = "Text"
DataValueField = "Value" OnSelectedIndexChanged = "rblAllDev_SelectedIndexChanged">
</asp:RadioButtonList>
<asp:CustomValidator ID="_valDev" runat="server" ControlToValidate = "_rblAllDev" Text = "*"
ErrorMessage="Please choose at leat one developer for this task" OnServerValidate = "AllDev_ServerValidate" />
</td>
</tr>
</table>
</EditItemTemplate>
The problem is that it looks like the CustomerValidator handler is not even being called after the user click the UPPDATE link on the GridView. I have put a break point inside the method but the method is not even being called.
protected void AllDev_ServerValidate(object sender, ServerValidateEventArgs args)
{
}
Am I missing something?
Thanks for helping.
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.
<asp:TemplateField>
<ItemTemplate>
<table width="540" cellpadding="5">
<tr>
<td align="left" style="width:60%;">
<img src='PurchaseHandler.ashx?ProductID=<%# Eval("ProductID")%>'
alt="<%# Eval("ProductName") %>" />
</td>
<td align="left">
<h3 style="text-align:left;">
<asp:Label ID="nameLabel" runat="server"
Text='<%# Eval("ProductName") %>' />
</h3>
<asp:Label ID="priceLabel" runat="server" Text='<%# Eval("Price") %>' />
<br />
<asp:LinkButton ID="cartLink" runat="server" Text="<b>Add to Cart</b>"
CommandName="Add" CommandArgument='<%# Eval("ProductID") %>' />
</td>
</tr>
</table>
</ItemTemplate>
</asp:TemplateField>
I'm using a shopping cart business object which contains fields not used for display in the GridView. What I'm attempting to do next in the RowCommand event handler is to retrieve the rest of the data fields from the selected row. This gives me the correct product ID from the selected row:
if (e.CommandName == "Add")
{
int productID = 0;
int.TryParse(e.CommandArgument as string, out productID);
// Big blank!
}
How can I grab the rest of the data fields from the selected row to populate my cart? By way of explanation, I can probably use the productID to dig into the DataSet pulled from Session state, and get the data that way. However, what I'm trying to determine is if there is a syntax similar to this that can be used in this situation?
DataRow[] rows = ds.Tables[0].Select("ProductID=" +
gridProducts.SelectedDataKey.Values["ProductID"].ToString());
DataRow row = rows[0];
One way to do this would be to use the command argument to store the row index (perhaps setting it in the on row created event).
You could then use code as below to access your row (code snipped from MSDN):
// Convert the row index stored in the CommandArgument
// property to an Integer.
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row that contains the button clicked
// by the user from the Rows collection. Use the
// CommandSource property to access the GridView control.
GridView customersGridView = (GridView)e.CommandSource;
GridViewRow row = customersGridView.Rows[index];
If you need to keep your command argument as the product id then you can use the code below to access the row:
GridViewRow row = (GridViewRow)(((LinkButton)e.CommandSource).NamingContainer);
You can then use the FindControl() method of the GridViewRow to select the controls that you need.
Label priceLabel = row.FindControl("priceLabel") as Label;
Edit after comments from OP
So if I'm correct, you want to access the DataItem of your row?
I don't think this is possible within a RowCommand event handler - I did a little bit of digging on other forums and apparently this property is only not null during DataBind - MSDN has this to say:
The DataItem property is available only during and after the RowDataBound event of a GridView control.
Looks like your method or something similar is the only way of linking back to the original objects in the RowCommand (hopefully someone proves me wrong)