Hi I'm having a bit of an issue with a asp.net repeater
I'm building a categories carousel with the dynamic categories being output by a repeater.
Each item is a LinkButton control that passes an argument of the category id to the onItemClick handler.
a page variable is set by this handler to track what the selected category id is....
public String SelectedID
{
get
{
object o = this.ViewState["_SelectedID"];
if (o == null)
return "-1";
else
return (String)o;
}
set
{
this.ViewState["_SelectedID"] = value;
}
}
problem is that i cant seem to read this value while iterating through the repeater as follows...
<asp:Repeater ID="categoriesCarouselRepeater" runat="server"
onitemcommand="categoriesCarouselRepeater_ItemCommand">
<ItemTemplate>
<%#Convert.ToInt32(Eval("CategoryID")) == Convert.ToInt32(SelectedID) ? "<div class=\"selectedcategory\">":"<div>"%>
<asp:LinkButton ID="LinkButton1" CommandName="select_category" CommandArgument='<%#Eval("CategoryID")%>' runat="server"><img src="<%#Eval("imageSource")%>" alt="category" /><br />
</div>
</ItemTemplate>
</asp:Repeater>
calling <%=SelectedID%> in the item template works but when i try the following expression the value of SelectedID returns empty..
<%#Convert.ToInt32(Eval("CategoryID")) == Convert.ToInt32(SelectedID) ? "match" : "not a match"%>
the value is being set as follows...
protected void categoriesCarouselRepeater_ItemCommand(object source, RepeaterCommandEventArgs e)
{
SelectedID = e.CommandArgument.ToString();
}
Any ideas whats wrong here?
Within the categoriesCarouselRepeater_ItemCommand code you've shown, you're assigning the CommandArgument to a property called 'SelectedCategory'.
Should this not be assigning the property to the 'SelectedID' property instead?
** EDIT..
The problem I see is one of two scenarios:
1) You are not rebinding the repeater with each postback, and therefore the expression within your ItemTemplate is not being evaluated - The output from the repeater will remain unchanged with each postback.
OR
2) You are rebinding the repeater control with each postback, however, upon clicking on your LinkButton for the first time, the repeater control is re-binded PRIOR to the ItemCommand event handler firing, and therefore, the 'SelectedID' property has not been set until after the repeater has finished being output.
If you were to click on one of your LinkButtons a 2nd time, the previously selected ID would be in viewstate at the time of the repeater control contents being rendered, and therefore be one step behind in rendering which category has been clicked, and so on...
Related
I have a page which lists a bunch of items in a datagrid.
Each item has a cooresponding remove link button, which removes the item from the list. In my event handler -- where the item is deleted -- I do a check to see if the item is the last item in the list. If it is the last item, I don't do a delete, but send an alert box telling the user that the item cannot be deleted. I am unsure how to get C# to trigger this alert box.
My code looks like the following:
In my aspx, I have a datagrid with various Link Buttons. Snippet of code as shown:
<ItemTemplate>
<asp:LinkButton runat="server" ID="Remove"
OnCommand="lnkRemove_Command" CommandArgument='<%# Eval("Id") %>
OnClientClick="return false;">
</asp:LinkButton>
</ItemTemplate>
In my code behind, my event handler looks like such:
private List<MyItem> _items;
protected void lnkRemove_Command(object sender, CommandEventArgs e)
{
int ID = Convert.ToInt32(e.CommandArgument);
MyItem item = MyItem.GetItemByID(id); //This gets the item cooresponding to the ID
if (_items.Count != 1)
{
//code to delete item
}
else
{
//Generate an alert box to tell the user that this item cannot be deleted.
//I have tried the following two lines of commented code, which didn't work for me
//Response.Write(#"<script language='javascript'>alert('HERE');</script>");
//Page.ClientScript.RegisterStartupScript(this.GetType(), "hwa", "alert('Hello World');", true);
}
}
In addition, it may be important to note that in my Page_Load, I already do a Context.RegisterResource(this, StyleSheet, Script). In other words, I have working JavaScript and CSS, which cooresponds with this code for other features of this page in MyFile.js
If possible, I would like to create a JS function in MyFile.js where I already have js functions which are triggered by various OnClientClicks, etc...
Is it possible to do something like this:
in MyFile.js
var GetAlertMessage = function()
{
alert("Can't delete this item");
}
and call this function in my C# function that I listed above?
Thanks in advance for the help.
You should treat this like any other validation routine. There should be a client-side validation function and a server-side validation function.
Client Side Validation
on each delete-able item, add an onclick="ValidateDeletion();" and class="deleteable-item"
function ValidateDeletion()
{
var itemCount = $(".deleteable-item").length;
if(itemCount == 1)
{
alert("Sorry, you cant delete this item.")
return false;
}
else
{
//let it pass through
}
}
I've got a pretty strange problem with my usercontrols that I'm working with. I'm coding some user controls to be used in a DotNetNuke module.
Basically I have a UserControl on my page that holds some controls and then there is a Placeholder where I am loading in a UserControl that has a GridView placed in it.
Basically here is my page structure
<asp:Panel runat="server" ID="pnlServiceType" Visible="false">
<uc:ServiceType runat="server" ID="ServiceType" />
</asp:Panel>
Within that user control are some form elements and then the following:
<asp:PlaceHolder runat="server" ID="phServices" />
That placeholder then has a user control added to it like so:
<p class="header"><asp:Label runat="server" ID="lblServiceHeader" Font-Bold="true" /></p>
<asp:GridView runat="server" ID="gvServices" AlternatingRowStyle-BackColor="#eaeaea" BorderStyle="None" GridLines="None"
AutoGenerateColumns="false" CellPadding="6" Width="100%" EnableViewState="false" OnRowEditing="gvServices_RowEditing">
When the user picks something in the DropDownList, I'm clearing the controls out of the Placeholder, and re-adding just a single UserControl for the set of records for whatever type they've picked like so
_serviceID = e.Value;
//Clear the controls out of the placeholder
phServices.Controls.Clear();
//Reset the count of grids for the OnInit() method
Session["GridCount"] = 0;
if (e.Value != "NULL")
{
PopulateServicesGrid(_service.GetServicesByFormType(Convert.ToInt32(e.Value)));
}
else
{
PopulateServicesGrid(_service.GetServicesByClient(Convert.ToInt32(_client)));
}
And the PopulateServicesGrid method:
private void PopulateServicesGrid(List<NOAService> services)
{
//Creates a LINQ grouping based on the Billing Codes
//Allows a super easy creation of grids based on the grouped billing codes
var query = services.Select(service => service.BillingCode).Distinct();
foreach (string code in query)
{
var servicesByCode = services.Where(service => service.BillingCode == code).ToList();
ServicesGrid servicesGrid = LoadControl("~/DesktopModules/LEL Modules/NOA/ServicesGrid.ascx") as ServicesGrid;
Label lblServiceHeader = servicesGrid.FindControl("lblServiceHeader") as Label;
GridView gvServices = servicesGrid.FindControl("gvServices") as GridView;
phServices.Controls.Add(servicesGrid);
servicesGrid.ID = code;
lblServiceHeader.Text = servicesByCode[0].FormTypeName;
gvServices.DataSource = servicesByCode;
gvServices.DataBind();
Session["GridCount"] = phServices.Controls.Count;
}
}
And on my ServiceType UserControl, on the PageInit, I'm readding the ServiceGrid usercontrol so that my grids show up across postbacks and aren't lost from the Placeholder
void NOAServiceType_Init(object sender, EventArgs e)
{
for (int i = 0; i < Convert.ToInt32(Session["GridCount"]); i++)
{
ServicesGrid servicesGrid = LoadControl("~/DesktopModules/LEL Modules/NOA/ServicesGrid.ascx") as ServicesGrid;
phServices.Controls.Add(servicesGrid);
}
}
The grids populate successfully and everything seems to work just fine. But for some reason, on my GridView, I have a CommandField of
<asp:CommandField ShowEditButton="true" ItemStyle-HorizontalAlign="Right" EditText="Edit" UpdateText="Update"
EditImageUrl="~/images/LELModules/appbar.edit.rest.png" CancelImageUrl="~/images/LELModules/appbar.close.rest.png" UpdateImageUrl="~/images/LELModules/appbar.check.rest.png"
ButtonType="Image" CausesValidation="false" />
When I click my Edit command on the Grid row, nothing happens. My grid doesn't lose its rows, the control is still there, everything seems like it should be ok. The RowEditing event doesn't fire until I click it a second time.
Any idea why this might be occuring?
UPDATE: I've managed to figure out that my SelectedIndexChanged handlers are effectively resetting the DataSource on the Grid contained by the UserControl when they are readded to the PlaceHolder. When the CommandField (Edit) is clicked though, the Init fires for the UserControl that holds the placeholder
ServiceType UserControl < `Init` fires here
-Form elements
-Placeholder which holds
--UserControl with GridView
The Init method loads up new instances of the UserControl and adds them to the PlaceHolder, but the DataSource is null. With EnableViewState=true it looks like the data is still bound, but if I handle PreRender, I can see that the DataSource on my gvServices | null
Is it even possible to edit rows like this on a GridView that is being added dynamically to a PlaceHolder over and over?
FIXED I found out what the issue was after referring to this article
http://www.west-wind.com/weblog/posts/2006/Feb/24/Overriding-ClientID-and-UniqueID-on-ASPNET-controls
It got me thinking, what if the IDs were getting changed? The controls are way nested. So I went and put a watch on the GridView's ID, ClientID, and UniqueID just to see. When the Control is loaded on my Init handler, it's assigned a super generic ID when it's added.
private void PopulateServicesGrid(List<NOAService> services)
{
//Creates a LINQ grouping based on the Billing Codes
//Allows a super easy creation of grids based on the grouped billing codes
var query = services.Select(service => service.BillingCode).Distinct();
foreach (string code in query)
{
var servicesByCode = services.Where(service => service.BillingCode == code).ToList();
ServicesGrid servicesGrid = LoadControl("~/DesktopModules/LEL Modules/NOA/ServicesGrid.ascx") as ServicesGrid;
Label lblServiceHeader = servicesGrid.FindControl("lblServiceHeader") as Label;
GridView gvServices = servicesGrid.FindControl("gvServices") as GridView;
phServices.Controls.Add(servicesGrid);
**servicesGrid.ID = code;**
lblServiceHeader.Text = servicesByCode[0].FormTypeName;
gvServices.DataSource = servicesByCode;
gvServices.DataBind();
Session["GridCount"] = phServices.Controls.Count;
}
}
I was setting the ID as something else. So when I was hitting the Edit RowCommand on my grid, it was reloading the controls again on Init and the IDs were being changed back from my custom set code (T2020, pulled from my database) to the generic ID again, it didn't know how to fire the event.
I hope this helps someone as I've lost at least 12 hours fixing this problem.
In asp.net, buttons can have postback urls (ie by specifying a PostBackUrl - I have used this to truncate querystring parameters in the past - by just specifying the page url without any parameters). This is super easy with a button.
Does anyone know what the best approach to doing this is with a dropdownlist? If I specify AutoPostBack (post back when the selection changes), there doesn't seem to be an easy way to modify the postback url (ie postback to the page without querystring parameters).
I'm guessing maybe doing a custom postback with javascript... but is there a better method - like a property as in the asp.net button that I am missing?
No there isn't property with DropDownList. You can redirect the user using Response.Redirect method and use Session collection to persists data between requests.
There isn't that property for DropDownList but you can do some tricks to add this functionality to your pages. First of all let me describe a situation why this property may be necessary for you:
You've got a page with a gridview filled from a database. For example a list of employees of your company. The fields are id, name, surname, jobname etc.
You can open this page from other pages of your project and then in some cases you have to select one of your employees in the gridview. So you need a parameter with id of that employee that you can pass to the gridview page.
Of course for this purposes you can use session variables but in some cases they are not accepted. For example session varibles aren't so good with the back button. You can press back many times, return to the gridview page from the browser history with selected employee but the session variable will contain the last set id and not the opened now! And now imagine that you have a delete button that do its job by the session id. You see one gridview row as the selected one but delete a completely different row.
So the best way to pass parameters to other pages is the query string. You can read it with ease and be sure that the back button will not destroy them.
Now when you are on the page and click the gridview rows you have to modify your url in order to the url id parameter matches the selected row. It can be done with linkbuttons inserted in each row with right filled PostbackUrl property. You click a linkbutton in the row, the linkbutton contains the postbackurl with the correct row id, the postback goes as you want to and both the selected row and the url are ok.
And now imagine that you are in more complicated situation. You've got a dropdownlist on your page which should filter list of employees in your gridview. For example by departments. So you must refill the gridview and get rid of id in the url because after refill you don't need the gridview to have any selected rows. But you can't do it, the dropdownlist doesn't have this magic property...
So here is the solution:
namespace myspace
{
public partial class EmployeePage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
//now you should get the correct url
//you can generate it right here but i prefer to use a special method to
//ensure that this url will be the same in all places of my code
string emptyEmpIdPostbackUrl = Utils.GetEmployeePageURL("");
//now call the main method
Utils.CreatePostbackUrl(this, "SetFilterUrl", emptyEmpIdPostbackUrl,
new List<WebControl> { ddlFilterCompany, ddlFilterDepartment, ddlFilterOwner,
ddlFilterType, ddlFilterDiscarded, ddlFilterChangeDate });
if (!IsPostBack)
{
...
}
}
...
}
public static class Utils
{
//page - your gridview page
//name - some custom name to ensure that different postbacks will work independently from each other
//url - the url with empty employee id
//controls - list of webcontrols for which you want to create postback url (i've got 6 dropdownlists on my own page)
public static void CreatePostbackUrl(Page page, string name, string url, List<WebControl> controls)
{
//create a hidden button with your postbackurl
Button btn = new Button();
btn.ID = name;
btn.PostBackUrl = url;
btn.Attributes.Add("style", "display: none;");
page.Form.Controls.Add(btn);
//register javascript that will simulate click on the hidden button
page.ClientScript.RegisterClientScriptBlock(page.GetType(), name + "Script",
"<script type=\"text/javascript\"> function " + name + "() {" +
"var btn = document.getElementById('" + btn.ClientID + "'); " +
"if (btn) btn.click();} </script>", false);
//and link this script to each dropdownlist in the list
foreach (WebControl ctrl in controls)
{
string attrName = "";
if (ctrl is DropDownList)
attrName = "onchange";
if (attrName != "")
ctrl.Attributes.Add(attrName, name + "()");
}
}
public static string GetEmployeePageURL(string empId)
{
return "emp.aspx" +
"?empid=" + empId;
}
}
}
After these manipulations you'll get the page with a hidden button and bunch of webcontrols that will be linked to this button and share its PostBackUrl property.
If you are wanting to POST directly to another page, use could try a hidden button approach
<asp:DropDownList ID="lstMyDropDown" runat="server" ClientIDMode="Static" onchange="javascript:$get('btnHidden').click(); ">
<asp:ListItem Value="0" Text="Some Value 1" />
<asp:ListItem Value="1" Text="Some Value 2" />
</asp:DropDownList>
<asp:Button ID="btnHidden" runat="server" ClientIDMode="Static" PostBackUrl="~/myProcessingPage.aspx" OnClientClick="javascript:if($get('lstPrinterModel').selectedIndex < 1){return false;}" style="display:none" />
Hi folks i have this terrible problems i hope any of you could help me first of all i have a ListView which has (lets say) 3 columns Id, Quantity, And an image button with an action.
the image button launch the function createparameter that splits the string into 2 int variables, but i want to get the first 1 from the textbox QuantityTextBox, What can i do to send the value of the textbox to the function, any ideas?
protected string CreateParameter(object arg1, object arg2)
{
return string.Concat(arg1, "|", arg2);
}
i wish there's a better way to do this than do a foreach of every list item and then find control because i dont care the other list items,
What you want to do will not work the way you want because the value of the textbox could be changed by the user. So it's not reasonable to try and bind it to the CommandArgument at runtime because there is no value there yet.
But when you handle the ItemCommand event for the ListView, you have access to which ListViewItem the button was clicked in, so you can use FindControl to get the textbox and look at its value.
For that to work, you will need to add a CommandName value to your ImageButton controls. And you would just pass in the product id in the command argument directly.
So, your button would look like this:
<asp:ImageButton ID="btnAdd" runat="server" Tooltip="Aggregar producto" CommandName="AddProduct"
CommandArgument="<%# Eval("IdProduct") %>" />
And your codebehind would look something like this (not tested):
protected void lv_Productos_OnItemCommand(object sender, ListViewCommandEventArgs e)
{
if (String.Equals(e.CommandName, "AddProduct"))
{
// Get a reference to your textbox in this item
TextBox textbox = e.Item.FindControl("QuantityTextBox") as TextBox;
if (textbox != null)
{
int quant = 0;
if (int.TryParse(textbox.Value, quant))
{
int prodId = (int)e.CommandArgument;
//do what you want with the quantity and product id
}
}
}
}
I have a DropDownList and a function that gets what the value is selected but the SelectedIndex and the SelectedValue always return the first item.
The DropDown code is
<asp:DropDownList ID="lstApps" runat="server" DataSourceID="sqlDataSource"
DataTextField="some_val" DataValueField="some_id"
TabIndex="5" >
</asp:DropDownList>
and the code (in a button click even of a button somewhere on the page)
int x = lstApps.SelectedIndex;
always returns 0 despite of what I might have selected. Is it due to auto postback being disabled or some other reason?
I guess! You need to use IsPostBack block in Page_Load event.
public void Page_Load()
{
if(!IsPostBack)
{
//put databinding code here.
}
}