Find controls in GridView - asp.net

I have something weird happening, maybe i don't know of something?
I am trying to populate a Drop Down List (in the editItemTemplate) and also, when the Grid View Loads populate a column, with strings instead of the id's that it contains now.
ASPX(the fiels that I have problem with are &
<asp:GridView ID="gvAdminArticleAdd".....
<asp:TemplateField HeaderText="invsId" SortExpression="invsId">
<EditItemTemplate>
<asp:DropDownList ID="ddl_invNames" runat="server" AutoPostBack="True" />
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="lbl_insLabel" runat="server" Text='<%# Bind("invsId") %>'></asp:Label>
</ItemTemplate>
<FooterTemplate>
<asp:DropDownList ID="ddl_invNamesNew" runat="server" AutoPostBack="True" />
</FooterTemplate>
</asp:TemplateField>
CodeBehind
protected void gvAdminArticleAdd_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//111111
//finding cotrols into the edit rows event
if (e.Row.RowState == DataControlRowState.Edit)
{
DropDownList ddlImages = (DropDownList)e.Row.FindControl("ddlImages");
ddlImages.DataSource = GetPdfs();
ddlImages.DataBind();
DropDownList ddlinvsNames = (DropDownList)e.Row.FindControl("ddl_invNames");
ArrayList invList = GetInvestigatorNames();
ddlinvsNames.DataSource = invList;
ddlinvsNames.DataBind();
}
//222222
//finding cotrols into rows
Label insLabel = (Label)e.Row.FindControl("lbl_insLabel");
int invsLabelId = int.Parse(insLabel.Text);
insLabel.Text = connection.GetInvsNameById(invsLabelId);
}
}
The problem that I have occur in the RowDataBound event, I can't figure it up what is wrong
//111111 and //22222 are working correctly(if I comment one of them), but not together. how can it be?
if I place them together I am getting an error on this line of code
int invsLabelId = int.Parse(insLabel.Text);
Object reference not set to an instance of an object.
so the error is in the previous line, but I can't figure why.

//111111 and //22222 are working correctly(if I comment one of them),
but not together. how can it be?
You do not need those two to work together. Only one will be available at a given time.
if (e.Row.RowState == DataControlRowState.Edit)
{
// EditItemTemplate - only controls inside EditItemTemplate are available here.
var ddlImages = (DropDownList)e.Row.FindControl("ddlImages");
var ddlinvsNames = (DropDownList)e.Row.FindControl("ddl_invNames");
}
else
{
// ItemTemplate - only controls inside ItemTemplate are available here.
var insLabel = (Label)e.Row.FindControl("lbl_insLabel");
}

The problem is that your dropDownList is added only during the EditMode. This you are retrieving in the if (e.Row.RowType == DataControlRowType.DataRow) code block. That is fine, you will be able to retrieve the dropdown list correctly. But in the same code block you are retrieving the Label ddl_invNames which will not be available in the edit mode, because you have added this label in the ItemTemplate. So the error must be in this place. However if you comment whole of this block, then the code goes directly to /222222, where you are trying to access the label, which will not be there at all during the edit mode of the row

Related

asp.net binding query output into dropdown list in gridview

this is for ticketing system where the tickets are in different status like 'open, rejected, closed, resolved..'
In asp.net i have a gridview and in the gridview there are textboxes and a dropdownlist.
i can get output from the database and get to populate it in the gridview and also the contents in the dropdown list are also displayed.
how can i get to bind the data of the dropdownlist in the grid to that of the output of the query. if the ticket is closed it should select closed, if the ticket is rejected it should select rejected.
in the onrowCommand, i fetch data from another table and populate into the dropdown list. this is the full list of status like 'oopen, rejected, closed, resolved..'
Your question is missing details like what markup you have used for gridview and also what code you have for RowDataBound event.
So, I have provided a sample answer that you can easily adapt to your situation.
I am assuming you have a gridview with an id of GridView1 that contains the following ItemTemplate ( other columns have been omitted since they are not needed to understand this approach).
You should have a hidden field in the template so you can store the current status of the row; also when you are binding your gridview you should be getting a column called Status for the row.
Sample Markup
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false"
OnRowDataBound="GridView1_OnRowDataBound">
<Columns>
<asp:TemplateField HeaderText = "Status">
<ItemTemplate>
<asp:HiddenField ID="hfStatus" runat="server" Value='<%# Eval("Status") %>' />
<asp:DropDownList ID="ddlStatus" runat="server">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
Then in your RowDataBound event where you are binding the dropdown for the row, you need to get the value of hidden field hfStatus and then set the selected item of dropdown using this value.
I have assumed that a method called GetStatusDropDownListData is there that gets the data for binding dropdown list.
Sample RowDataBound event
protected void GridView1_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Find the DropDownList in the Row
DropDownList ddlStatus = (e.Row.FindControl("ddlStatus") as DropDownList);
ddlStatus.DataSource = GetStatusDropDownListData();
ddlStatus.DataTextField = "Status";
ddlStatus.DataValueField = "Status";
ddlStatus.DataBind();
//Select the Status in DropDownList
string currentStatus = (e.Row.FindControl("hfStatus") as HiddenField).Value;
ddlStatus.Items.FindByValue(currentStatus).Selected = true;
}
}
i had used this code and its working now:
in asp file:
' Visible = "false" />
in the .cs file
string currentStatus = (e.Row.FindControl("lblStatus") as Label).Text;
ddlStatus.Items.FindByValue(currentStatus).Selected = true;

DetailsView: How to set a HiddenField value using the CommandArgument on a New command?

I have inherited some code that has a GridView and a DetailsView in a webpart control.
The DetailsView is able to create two different kinds of an object e.g. TypeA and TypeB.
There's a dropdown list that filters the GridView by object type and the DetailsView has an automatically generated Insert button.
<asp:DetailsView ID="myDetailsView"
AutoGenerateInsertButton="True"
AutoGenerateEditButton="True"
AutoGenerateRows="false"
OnItemUpdating="OnItemUpdating"
DefaultMode="ReadOnly"
OnDataBound="OnDetailsViewBound"
OnItemInserting="OnItemInserting"
OnModeChanging="OnDetailsViewModeChanging"
runat="server">
I have been asked to:
remove the filter on the GridView; and
split the New buttons/links into two so there's a separate button for creating each type of object.
Removing the filter means that I need some other way to track what kind of object we're creating.
I have split the New links by changing the above to:
<asp:DetailsView ID="myDetailsView"
AutoGenerateInsertButton="False"
AutoGenerateEditButton="True"
AutoGenerateRows="false"
OnItemUpdating="OnItemUpdating"
DefaultMode="ReadOnly"
OnDataBound="OnDetailsViewBound"
OnItemInserting="OnItemInserting"
OnModeChanging="OnDetailsViewModeChanging"
runat="server">
and adding
<FooterTemplate>
<asp:TemplateField>
<ItemTemplate>
<asp:LinkButton runat="server" ID="lnkCreateNewTypeA" CommandName="New" CommandArgument="TypeA" CssClass="buttonlink">New Type A</asp:LinkButton>
<asp:LinkButton runat="server" ID="lnkCreateNewTypeB" CommandName="New" CommandArgument="TypeB" CssClass="buttonlink">New Type B</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
</FooterTemplate>
I haven't yet removed the filter so the changes currently function the same as before, as I'm using the New command.
What I was hoping to be able to do is somehow capture the New event so I can put the CommandArgument value into a hidden field, that the DetailsView would then use to determine which type of object it's creating and also to show/hide fields.
When I put breakpoints in all of the event handlers in my code, the first one to break is OnDetailsViewModeChanging, which doesn't have access to the CommandArgument.
OnItemCommand (if it's hooked up) is triggered when any button within the DetailsView is pressed and does give me access to the CommandArgument but I'm not sure what exactly needs to be done within this method to mimic the chain of events that occurs when you use automatically generated buttons.
Is my only option for retrieving the CommandArgument to capture it in the OnItemCommand event handler or is there some other event that is triggered on the New command?
Can anyone explain to me the sequence of events that occurs when the New command is triggered?
I read somewhere that it changes the mode to Insert but I don't know what else it does. I believe the OnItemInserting method isn't called until the "Insert" link is clicked.
Any help would be gratefully received!!
Edit:
I have found this link on DetailsView events but it hasn't answered my question.
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.detailsview_events.aspx
Edit:
I have tried adding the following:
in ascx:
<asp:DetailsView ID="myDetailsView"
...
OnItemCommand="OnItemCommand"
...
runat="server">
...
<asp:TemplateField HeaderText="Object Type" HeaderStyle-CssClass="columnHeader">
<ItemTemplate>
<asp:HiddenField runat="server" ID="hidObjectType" Value=""/>
<asp:Label runat="server" ID="lblObjectType"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
in code behind:
protected void OnItemCommand(object sender, DetailsViewCommandEventArgs e)
{
if (e.CommandName.Equals("New"))
{
var objectType = e.CommandArgument.ToString();
HiddenField typeHidden = this.myDetailsView.FindControl("hidObjectType") as HiddenField;
if (typeHidden != null)
{
typeHidden.Value = objectType;
}
Label typeLabel = this.myDetailsView.FindControl("lblObjectType") as Label;
if (typeLabel != null)
{
typeLabel.Text = objectType;
}
}
}
I found that I didn't need to set the mode (this.myDetailsView.ChangeMode(DetailsViewMode.Insert);) in this method, as the OnDetailsViewModeChanging event handler still triggered.
This finds the controls and sets the values on them correctly. If I check the values again in OnDetailsViewModeChanging, their values are still set but as part of the logic in this method, there is a call to
this.myDetailsView.DataBind()
which causes a postback and at this point, the values are lost. I tried adding
EnableViewState="True"
but this made no difference. I've reviewed the page lifecycle (http://spazzarama.files.wordpress.com/2009/02/aspnet_page-control-life-cycle.pdf) and thought that maybe this.EnsureChildControls() would help but it's also made no difference.
An alternative would be to store the value in the session but I'd rather not.
As far as I can tell there is no event for capturing the "New" command aside from OnItemCommand, which captures all commands. (NOTE: You will need to make sure that CausesValidation="False" is set on your LinkButton or the code won't break into OnItemCommand).
When stepping through the code, the following occurred:
After the linkbutton was pressed, OnItemCommand is triggered. CommandName = "New" and here I could retrieve the CommandArgument
Next OnModeChanging is triggered. e.NewMode = "Insert". From all examples I've seen, here you call ChangeMode on the DetailsView and then call Databind() on it
Next OnDataBound is triggered as a result of calling Databind()
I didn't find a way to retain the value of the hidden variable between the various events so I ended up using a session variable. Code is below in case anyone wants it.
DetailsView declaration in the ASCX:
<asp:DetailsView ID="myDetailsView"
AutoGenerateInsertButton="False"
AutoGenerateEditButton="True"
AutoGenerateRows="false"
OnItemInserting="OnItemInserting"
OnItemUpdating="OnItemUpdating"
OnItemCommand="OnItemCommand"
DefaultMode="ReadOnly"
OnDataBound="OnDetailsViewBound"
OnModeChanging="OnDetailsViewModeChanging"
runat="server">
In the code-behind:
constant declarations...
private const string SESSIONKEY_MYVALUE = "MyValue";
private const string DEFAULT_OBJECTTYPE = "TypeA";
OnItemCommand event handler...
protected void OnItemCommand(object sender, DetailsViewCommandEventArgs e)
{
if (e.CommandName.Equals("New", StringComparison.InvariantCultureIgnoreCase))
{
var objectType = e.CommandArgument.ToString();
HiddenField typeHidden = this.myDetailsView.FindControl("hidObjectType") as HiddenField;
if (typeHidden != null)
{
typeHidden.Value = objectType;
}
HttpContext.Current.Session[SESSIONKEY_MYVALUE] = objectType;
}
}
OnModeChanging event handler....
protected void OnDetailsViewModeChanging(Object sender, DetailsViewModeEventArgs e)
{
if (e.NewMode == DetailsViewMode.Insert)
{
this.myDetailsView.ChangeMode(DetailsViewMode.Insert);
this.myDetailsView.DataBind();
}
}
OnDataBound event handler...
protected void OnDetailsViewBound(object sender, EventArgs e)
{
if (this.myDetailsView.CurrentMode == DetailsViewMode.Insert)
{
var sessionVar = HttpContext.Current.Session[SESSIONKEY_MYVALUE];
var objectType = sessionVar == null ?
DEFAULT_OBJECTTYPE :
sessionVar.ToString();
var typeHidden = this.myDetailsView.FindControl("hidObjectType") as HiddenField;
if (typeHidden != null)
{
typeHidden.Value = objectType;
}
}
}

ASP.Net, Datagrid: render column differently based upon value?

I've looked and looked and I'm not seeing the answer to this.
I have a datetime value that's getting bound to a datagrid. I want to display the column as either the datetime, or if said datetime is null, an asp:button for the users to click.
I can't seem to find specific information on how to do it. My initial approach was <% if blah blah then %>, but I can't seem to get at the dataitem in that manner. I've also looked at events, but nothing is jumping out at me as being the solution (I'm sure I'm wrong, I'm just not seeing it).
Any suggestions?
Assuming that you actually mean GridView instead of DataGrid, otherwise it would work similarly(ItemDataBound etc.).
You could use a TemplateField with a Label and a Button and switch visibility of both controls in RowDataBound:
protected void Grid_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
var row = ((DataRowView)e.Row.DataItem).Row;
DateTime? date = row.Field<DateTime?>("DateColumn");
var lblDate = (Label)e.Row.FindControl("LblDate");
var btnDate = (Button)e.Row.FindControl("BtnDate");
lblDate.Visible = date.HasValue;
btnDate.Visible = !date.HasValue;
if (date.HasValue) lblDate.Text = date.ToString();
}
}
aspx:
<asp:GridView ID="GridView1" AutoGenerateColumns="false" OnRowDataBound="Grid_RowDataBound" runat="server">
<Columns>
<asp:TemplateField HeaderText="DateColumn">
<ItemTemplate>
<asp:Label ID="LblDate" runat="server"></asp:Label>
<asp:Button ID="BtnDate" Text="click me" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
You should use Gridview if you are using ASP.NET 3.5 or higher. Using a templatefield column, add a button and label. In the rowdatabound event, you should show only the button or the label, using the Visible property, depending on whether there's a date or not.

how to access templatefield from code behind

the reason why i am looking to update dynamic is because i am using objectdatasource and my objectdatasource have a collection of object and within that object i have another object that i wanted to access so for an example:
+Student
......
......
......
-Courses
.........
.........
Name
Update end
how do i bind templatefield from code-behind?
<asp:Gridview ID="gridview1" runat="Server">
<columns>
<asp:TemplateField HeaderText="Name" SortExpression="Name">
<ItemTemplate>
</ItemTemplate>
</asp:TemplateField>
</columns>
</asp:Gridview>
First of all define your key field in GridView control, just add net attribute to GridView markup: datakeynames="StudentID".
You can use both event handler for GridView: RowDataBound or RowCreated. Just add one of this event handler and find there control that is placed in your ItemTemplate. Like here, for instance:
void ProductsGridView_RowCreated(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
// Retrieve the LinkButton control from the first column.
Label someLabel = (Label)e.Row.FindControl("someLabel");
if (someLabel != null)
{
// Get Student index
int StudentId = (int)GridView.DataKeys[e.Row.RowIndex].Values[0];
// Set the Label Text
// Define here all the courses regarding to current student id
someLabel.Text = //
}
}
}
This example was gotten from MSDN
Here are some code samples from MSDN:
http://msdn.microsoft.com/en-us/library/aa479353.aspx
These are in VB but you should be able to locate C# also :-)
If you follow this link and scroll down you will find a code sample:
http://bytes.com/topic/asp-net/answers/624380-gridview-generated-programmatically

How do I find the Client ID of control within an ASP.NET GridView?

I have a asp:GridView which contains a asp:TextBox within a TemplateField. I would like to obtain it's ID for use in javascript. Something like this:
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="textDateSent" runat="server" />
<input type="button" value='Today'
onclick="setToday('<%# textDateSent.ClientID %>');" />
</ItemTemplate>
</asp:TemplateField>
But when I compile, I get an error:
The name 'textDateSent' does not exist in the current context
Anybody know how to get the client ID of this TextBox?
Try this:
<asp:TemplateField>
<ItemTemplate>
<asp:TextBox ID="textDateSent" runat="server">
</asp:TextBox>
<input type="button" value='Today' onclick="setToday('<%# ((GridViewRow)Container).FindControl("textDateSent").ClientID %>');" />
</ItemTemplate>
</asp:TemplateField>
Maybe you don't want to do it where you need the ClientID. Check out this post here where the controls in a row are referenced in a generic way.
Change <%# textDateSent.ClientID %> to <%= textDateSent.ClientID %>.
Argh, you may need to use the OnDataBinding event of the grid view. Then put a literal control in your javascript. Then you can get the clientID of the text box and feed that into your literal control.
protected void GridViewName_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//Create an instance of the datarow
DataRowView rowData = (DataRowView)e.Row.DataItem;
//locate your text box
//locate your literal control
//insert the clientID of the textbox into the literal control
}
}
Look here for a great detailed tutorial on working within this context.
You can get client id like this:
protected void Gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
string strClientID = ((TextBox)e.Row.FindControl("txtName")).ClientID;
}
}
This will give unique client ID for each textbox in all rows.
I just do this...
var tbl = document.getElementById('<%=GridView.ClientID%>');
var checkBox = tbl.rows[i].cells[11].getElementsByTagName("input")[0].id;
the cell should always be the same and it gets rendered into an input. You may have to change the number at the end if you have more then one input in that cell. This will give you the new clientid/id of the input object (checkbox or whatever)
This is what I did. In the aspx page I just passed the entire object to the javascript function, so I didn't even meed to client id. In my case the object was a drop down list in the EditItemTemplate of the GridView. I added an html onchange(this) event in the aspx code.
<asp:DropDownList ID="custReqRegionsDDL" runat="server" onchange='custReqRegionsDDLOnChange(this)'>
</asp:DropDownList>
here is my javascript
function custReqRegionsDDLOnChange(myDDL)
{
alert('selected text=' + myDDL.options[myDDL.selectedIndex].text);
}

Resources