I have a asp:ListView control that I bind with a List<CustomObject>.
When Editing records in this ListView control, I can always get the Unique Id of record being edited by using:
int id = Convert.ToInt32(lstView1.DataKeys[e.NewEditIndex].Value);
Is it possible to get the whole object <CustomObject> that is being edited, using any of the ListView properties?
I just figured that out,
We can get the object being edited using following code-
protected void lstView1_ItemDataBound(object sender, ListViewItemEventArgs e)
{
ListViewDataItem objCurrentItem = (ListViewDataItem)e.Item;
**CustomObject obj = (CustomObject)objCurrentItem.DataItem;**
if (objCurrentItem.DisplayIndex == lstView1.EditIndex)
{
TextBox txtTitle = (TextBox)objCurrentItem.FindControl("txtTitle");
txtTitle.Text = obj.Title;
}
}
Here is the answer to your comment to my question:
Yes, the reason it is null in itemcommand and works fine in itemdatabound is that the location itemcommand is not correct for reading this value. You will always get the DataItem null in ItemCommand, no matter what you do. The reason lies in the control life cycle. The control gets initialized, created and then only does any other event related to the control can fire. During control creation the CreateControlHierarchy is called which then uses the DataBind event to create and databind the child controls. At that time the DataItem is live and is not null. Before that and after that it is always null, because its role lies only for that much time span.
By the way the DataItem you are looking at is the item from the related datasource that is being used to databind the listview. The datasource is used only during databinding, hence the DataItem is available only during Item Databound.
Hope this helps !
When you click on the edit for a given item in the listview the ItemCommand event gets fired. The arguments for that event tell that you can get the list item for which that event was fired. You will have to typecast that item properly to get the information you require. The itemcommand event looks like this
protected void ListView1_ItemCommand(object sender, ListViewCommandEventArgs e)
{
}
you have e.Item to use from the ListViewCommandEventArgs.
You item updating you don't have the object available for modifying. You only have the collection of the properties and their values in the new values and old values collections that you get from event arguments. I suppose you can edit the properties of the item over there. Its more or less similar to editing the object itself, because eventually these property values will get transferred to the object using reflection.
<asp:ListView runat="server" ID="list" OnItemCommand="listVideo_ItemCommand">
<ItemTemplate>
<asp:LinkButton ID="btDelVideo" runat="server" Text="Delete" OnClientClick="return confirm('Confirm delete ?');" CommandArgument='<%# Eval("KeyID") %>' CommandName="DELETE" />
<asp:LinkButton ID="btEditVideo" runat="server" Text="Edit" CommandArgument='<%# Eval("KeyID") %>' CommandName="EDIT" />
</ItemTemplate>
</asp:ListView>
protected void list_ItemCommand(object sender, ListViewCommandEventArgs e)
{
int videoId = (int)e.CommandArgument;
switch (e.CommandName)
{
case "DELETE":
//Implement Delete event
goto default;
case "EDIT":
//Implement Edit event
goto default;
default:
//Rebind listview
break;
}
}
}
Related
I have a feeling I'm missing something really obvious, I'm not able to capture the selected value of my DropDownList; the value renaubs the first item on the list. I have set the DropListList autopostback property to true. I have a SelectedIndexChangedEvent which is pasted below. This is NOT on the master page.
protected void ddlRestCity_SelectedIndexChanged(object sender, EventArgs e)
{
if (IsPostBack)
{
r_city = ddlRestCity.SelectedValue.ToString();
}
}
Here is the DropDownList control:
<asp:DropDownList ID="ddlRestCity" runat="server"
Width="100px" AutoPostBack="True"
onselectedindexchanged="ddlRestCity_SelectedIndexChanged">
</asp:DropDownList>
Thanx in advance for your help!
My off the cuff guess is you are maybe re-populating the list on a post back and that is causing the selected index to get reset.
Where is your DataBind() call? Are you checking !IsPostBack before the call? For example:
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
ddlRestCity.DataSource = ...;
ddlRestCity.DataBind();
}
}
Explanation: If you don't check for !IsPostBack before DataBind(), the list will re-populate before SelectedIndexChanged is fired (because Page.Load fires before child events such as SelectedIndexChanged). When SelectedIndexChanged is then fired, the "selected item" is now the first item in the newly-populated list.
What is r_city?
If it's a textbox, then you need to do something like r_city.text = ...
Also -- you might consider removing your postback check. Usually, that's most useful in the page.onload event, and usually, you're checking for if NOT ispostback...
I have a repeater that is looping a user control, like this:
<asp:Repeater ID="repItems" runat="server" EnableViewState="false"
OnItemCommand="repItems_ItemCommand">
<ItemTemplate>
<dmg:confirmItem runat="server"
OnDataBinding="confirmitemItem_DataBinding"
Basket="<%# Container.DataItem %>" />
</ItemTemplate>
</asp:Repeater>
My code behind looks like this:
public void BindItems(List<ShopBasket> baskets)
{
_baskets = baskets;
repItems.DataSource = baskets;
repItems.DataBind();
}
My custom user control looks like this:
public ShopBasket Basket;
protected void Page_Load(object sender, EventArgs e)
{
imgItem.ImageUrl = ShopImagePath + Basket.ImageFilename;
...etc...
}
All works brilliantly the first time around, the basket items are bound to Basket objects and everything is great.
However, when I receive an ItemCommand from my repeater, and update the basket contents (Note: No adding or removing is done here, just updates the quantity) then I rebind to see the latest values, and BOOM! Null reference - no Basket object in the user control Page_Load. This is despite tracing through to see that the BindItems() method is called as usual, and the Baskets are there.
I presume this has something to do with the life cycle but it has me beat.
Any ideas?
Thanks
Duncan
It's a little dangerous to have a public field store an item being bound, especially when you have multiple items. A safer way to do it is to extract the Basket as the DataItem bound to the repeater, and do something with it that way in the repeater ItemCommand event. ItemDataBound would be even safer as you know the basket would be existing (since it's data bound), Page_Load is not a safe option here...
HTH.
Currently struggling with a problem that I've encountered variations on in the past. At the moment a worthwhile solution escapes me, but it seems such an obvious issue that I can't help wondering whether or not there's a "best practice" approach I should adopt.
Without code, here's the issues in a nutshell:
page has databound control (a repeater) which isn't populated until user inputs data and clicks a button.
Repeater item template contains a button
User clicks button, page posts back. On load, the repeater is actually empty so event is never handled because the originating control no longer exists
Go back to the beginning of wretched cycle
I've confirmed that this is the problem because if you provide the repeater with some static data on page load, everything works fine. But of course that's no use because it has to be populated dynamically.
Is there a commonly approved way round this headache? I can store the data in session and re-use it on page load, but it seems terribly clumsy.
Cheers,
Matt
If the event is being fired by a button within a repeater then this would bubble up to the repeaters ItemCommand event. Using a buttons CommandName and CommandArgument parameters you can then identify which button was clicked and act accordingly. Below is some basic markup and code behind to demonstrate the approach:
HTML:
<asp:Repeater ID="rptTest" runat="server" onitemcommand="rptTest_ItemCommand"
onitemdatabound="rptTest_ItemDataBound">
<ItemTemplate>
<p>
<asp:Button ID="btnTest" runat="server" />
</p>
</ItemTemplate>
</asp:Repeater>
<asp:Button ID="btnLoad" runat="server" Text="Load" onclick="btnLoad_Click" />
Code behind events:
protected void rptTest_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
Button button = (Button)e.Item.FindControl("btnTest");
button.Text = string.Format("Button {0}", e.Item.DataItem.ToString());
button.CommandName = e.Item.ItemIndex.ToString();
}
protected void rptTest_ItemCommand(object source, RepeaterCommandEventArgs e)
{
Response.Write(string.Format("Postback from button {0}", e.CommandName));
}
protected void btnLoad_Click(object sender, EventArgs e)
{
List<int> list = new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
rptTest.DataSource = list;
rptTest.DataBind();
}
Hopefully i've understood the problem and this helps.
If any of your controls are created dynamically, then they have to be recreated during post back in order for the events etc to get hooked back up.
If this is the case, take a look at a control built by a guy named Denis Bauer. We use this with just some slight modifications and it's perfect.
I´ve read most posts here but i can´t figure out why the "CheckedChanged" Event is not firing. Here is my situation.
I´m using a Repeater to generate Items out of a Database. Each ReapeaterItem should include an UpdatePanel, because i have to Update the Controls inside the UpdatePanel and do not want to reload the complete page. Inside these dynamically generated UpdatePanels (each RepeaterItem has one) i´m adding up to three Checkboxes dynamically (based on the Database). These Checkboxes need to fire the "CheckedChanged" event, because on some conditions i want to enable/disable/check/uncheck Checkbox1, 2 or 3 based on business logic. ... Hope you got this so far. I´m adding all Controls and have the EventHandler Added. But the generated Code does not reflect the Event Handler. I tried OnItemDataBound, OnItemCreated, PreRender, ... Events to add the Eventhandler too, but i was not able to find the CheckBox-Control with the ID.
I´m totally lost with this and on the way to use Buttons instead of Checkboxes. From what i read so far is that with Buttons i can use the CommandName from the Button and the ItemCommand-Event from the Repeater to get a workaround, but then i need to reflect the "Check" on the Page in some way.
btw, every Repeater (8) sits inside an ajaxtoolkit-accordion control.
Here i give you some Code:
aspx-Page
<asp:Repeater ID="RepeaterAccordionPane2" runat="server">
<ItemTemplate>
HTML Stuff<%# DataBinder.Eval(Container.DataItem, "Header")%>HTML Stuff<%# DataBinder.Eval(Container.DataItem, "Beschreibung")%></td>
<asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode=Conditional>
<ContentTemplate>
</ContentTemplate>
</asp:UpdatePanel>
HTML Stuff
</ItemTemplate>
</asp:Repeater>
Here is the Page_Load Part
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
dvAlleArtikel = new System.Data.DataView(...Database...);
[... some other code here ...]
RepeaterAccordionPane2.DataSource = dvAlleArtikel;
//RepeaterAccordionPane2.ItemCreated +=new RepeaterItemEventHandler(RepeaterAccordionPane2_ItemCreated);
//RepeaterAccordionPane2.PreRender +=new EventHandler(RepeaterAccordionPane2_PreRender);
RepeaterAccordionPane2.DataBind();
int nUpdatePanelIndex = 0;
foreach (Control crInRepeater in RepeaterAccordionPane2.Controls)
{
if (crInRepeater.GetType() == typeof(RepeaterItem))
{
foreach (Control crInRepeaterItem in crInRepeater.Controls)
{
if (crInRepeaterItem.GetType() == typeof(UpdatePanel))
{
LiteralControl litTabelleBeginn = new LiteralControl("<table width=\"100%\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\">");
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litTabelleBeginn);
if (dvAlleArtikel[nUpdatePanelIndex]["ArtNr1"].ToString() != "0")
{
CheckBox CheckBox1 = new CheckBox();
CheckBox1.ID = dvAlleArtikel[nUpdatePanelIndex]["ArtNr1"].ToString();
CheckBox1.Text = (dvAlleArtikel[nUpdatePanelIndex]["CheckBoxLbl1"].ToString() == "" ? "leer" : dvAlleArtikel[nUpdatePanelIndex]["CheckBoxLbl1"].ToString());
CheckBox1.AutoPostBack = true;
CheckBox1.CheckedChanged +=new EventHandler(CheckBox1_CheckedChanged);
LiteralControl litNeueTabellenZeileBeginn = new LiteralControl("<tr><td width=10><img src=\"images/helper/spacer.gif\" width=\"10\"></td><td height=\"20\">");
LiteralControl litNeueTabellenZeileEnde = new LiteralControl("</td><td width=\"100\" height=\"20\">" + dvAlleArtikel[nUpdatePanelIndex]["ArtPrice1"].ToString() + " € </td></tr>");
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litNeueTabellenZeileBeginn);
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(CheckBox1);
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litNeueTabellenZeileEnde);
}
[... some other code here...]
LiteralControl litTabelleEnde = new LiteralControl("</table>");
((UpdatePanel)crInRepeaterItem).ContentTemplateContainer.Controls.Add(litTabelleEnde);
nUpdatePanelIndex++;
}
}
}
}
This code is never reached:
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
int foo = 0;
}
This is the CheckBox-Code generated:
<input id="AccordionPane2_content_RepeaterAccordionPane2_ctl00_6200" type="checkbox" name="AccordionPane2_content$RepeaterAccordionPane2$ctl00$6200" onclick="javascript:setTimeout('__doPostBack(\'AccordionPane2_content$RepeaterAccordionPane2$ctl00$6200\',\'\')', 0)" />
The Event is generated, but when i click the Checkbox all Content in the UpdatePanel is gone and the CheckedChanged-EventHandler is not fired.
What am i doing wrong?
Thanks to all advice, i´m really stuck.
mk
The first time the page loads you are adding all the checkboxes to the Controls collection, and they get rendered. When you do a postback (through the CheckBox's AutoPostBack) you have a check if(!IsPostBack) that doesn't allow the checkboxes to be added to the Controls collection on the postback. Because of that, you won't see the controls and the page, and when the page lifecycle tries to call the events (which occurs AFTER Page_Load), the controls that created the events are no longer there.
You will need to refactor your Page_Load method so it does two things - 1, regardless of the value of IsPostBack bind the repeaters and create the dynamic controls. 2, if IsPostBack==false, i.e., an initial load, then set the values of the dynamic controls. you don't want to set the values of the dynamic controls when IsPostBack==true because then you will lose the values the user entered.
also, just a note:
if (crInRepeater.GetType() == typeof(RepeaterItem))
can be rewritten as:
if (crInRepeater is RepeaterItem)
I have a table that has two columns:
CommunityID
PersonID
And A "People" table that has (among other things):
FirstName
LastName
I would like to display a different DataGrid for each community, each datagrid having only the people that are part of that community. I would like to do this without using 4 seperate SqlDataSources.
A Repeater looks like a good way, with a DataGrid inside the ItemTemplate, but I can't seem to make heads or tails of getting that to work with the different values for each repetition.
If anyone has any suggestions on better ways to do this, I'd be very appreciative, as this is one of my first forays into the world for ASP.NET
Thanks,
Mike
Personally I wouldn't use a DataGrid control, since it restricts your control over your output and they've been replaced by the newer GridView & ListView controls (although DataGrid is not obsolete so feel free to use it if you want). You may want to consider using the alternatives but you aren't required to do so.
To do what you're looking for, you would have markup like the following:
<asp:Repeater runat="server" ID="myRepeater"
onitemdatabound="Repeater_ItemDataBound">
<ItemTemplate>
<asp:DataGrid runat="server" ID="myDataGrid">
</asp:DataGrid>
</ItemTemplate>
</asp:Repeater>
Then you'll wire up the markup with the following code-behind:
protected void Page_Load(object sender, EventArgs e)
{
myRepeater.DataSource = new Object[0];
myRepeater.DataBind();
}
protected void Repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
DataGrid dg = (DataGrid)e.Item.FindControl("myDataGrid");
object o = e.Item.DataItem;// Cast the DataItem as whatever
// your Repeater's DataSource is
// ...
// Do whatever you need to get the
// data source for your DataGrid here
// ...
dg.DataSource = DataGridSourceObjectHere;
dg.DataBind();
}
The key is the Repeater's ItemDataBound event, which is the method called every time a repeater row is created. This is where you can data bind your DataGrid source. You can put any logic you need to within this method using the RepeaterItemEventArgs parameter to access the data item you bound to your Repeater.