GridView row update and DropList - c#

I have a gridview with column that have droplist when enter edit mode:
<asp:TemplateField HeaderText="genre" SortExpression="genre">
<EditItemTemplate>
<asp:DropDownList ID="DropDownList2" runat="server"
DataSourceID="SqlDataSource1" DataTextField="name" DataValueField="name">
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("genre") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Now i want to take it to UpdateParameters of SqlDataSource:
<UpdateParameters>
<asp:ControlParameter ControlID="DropDownList2" Type="string" PropertyName="SelectedValue" Name="genre" />
</UpdateParameters>
But when i pressed he give me Error msg
Could not find control 'DropDownList2' in ControlParameter 'genre'.
Any idea why?

DropDownList2 is a nested control located under the Grid; therefore, your SqlDataSource control does not have visibility at all of the DropDownList2.
You could try assigning the value on the code behind by using the Updating event:
protected void SqlDataSource_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
e.Command.Parameters["#genre"].Value = GetDropDownListValue();
}
Note: You will need to use FindControl("DropDownList2") in GetDropDownListValue()

Related

GridView display text rather than foreign key

I have just started to learn how to use the Gridview Control to display SQL data. I have been able to get almost everything to work except for displaying the more user friendly information for one of my data fields that I populate from a lookup table. The entire concept of the page I want to be able to Update, Insert and Delete new records too and for some reason I could not get these options to work when I was using the SqlDataSource so I use LinqDataSource and all is now working (except I haven’t figured out Insert yet…a separate question)
I am also using the controls tabs in Visual Studio to choose and edit the attributes of the controls so kind of using the wizards and not hand coding the example.
What I cannot figure out is how to make my column with employeetypeid that contains the foreign key from the employeetypelookup table to show the employeetype text value for the user so this makes more sense. I found a “Walkthrough: Displaying a Drop-Down List While Editing in the GridView Web Server Control“ and this works perfectly. When I go into edit mode the dropdownlist shows the employeetype text and when I choose a different type, the appropriate employeetype id gets stored in the database.
So how can I modify something (the Datasource???) to display the employeetype text in the DataGrid.
<asp:LinqDataSource ID="LinqDataSource1" runat="server" ContextTypeName="SNRmain.SNRmainDataContext" EntityTypeName="" OrderBy="lastname, preferredfirstname" Select="new (personnelid, lastfirstname)" TableName="masterpersonnellastpreferreds"></asp:LinqDataSource>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" DataSourceID="LinqDataSource1" DataTextField="lastfirstname" DataValueField="personnelid">
</asp:DropDownList>
<asp:LinqDataSource ID="LinqDataSource2" runat="server" ContextTypeName="SNRmain.SNRmainDataContext" EnableDelete="True" EnableInsert="True" EnableUpdate="True" EntityTypeName="" TableName="tblappointmentdates" Where="personnelid == #personnelid" OrderBy="startdate desc">
<WhereParameters>
<asp:ControlParameter ControlID="DropDownList1" Name="personnelid" PropertyName="SelectedValue" Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="snrappointmentid" DataSourceID="LinqDataSource2">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="startdate" HeaderText="startdate" SortExpression="startdate" />
<asp:BoundField DataField="endingdate" HeaderText="endingdate" SortExpression="endingdate" />
<asp:TemplateField HeaderText="employeetypeid" SortExpression="employeetypeid">
<EditItemTemplate>
<asp:DropDownList ID="DropDownList2" runat="server" DataSourceID="LinqDataSource3" DataTextField="employeetypetext" DataValueField="employeetypeid" SelectedValue='<%# Bind("employeetypeid", "{0}") %>'>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1" runat="server" Text='<%# Bind("employeetypeid") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="apptcomment" HeaderText="apptcomment" SortExpression="apptcomment" />
<asp:BoundField DataField="dateentered" HeaderText="dateentered" SortExpression="dateentered" />
</Columns>
</asp:GridView>
<asp:LinqDataSource ID="LinqDataSource3" runat="server" ContextTypeName="SNRmain.SNRmainDataContext" EntityTypeName="" OrderBy="employeetypetext" Select="new (employeetypeid, employeetypetext)" TableName="tblemployeetypelookups">
</asp:LinqDataSource>
I have tried to modify the LinqDataSource2 to include a statement like the one below but that does not work and I get an error that does not make sense to me. "System.Web.Query.Dynameic.ParseException: Syntax error.
<asp:LinqDataSource ID="LinqDataSource2" runat="server" ContextTypeName="SNRmain.SNRmainDataContext" EntityTypeName="" Select="snrappointmentid,
personnelid, startdate,
endingdate, employeetypeid,
tblemployeetypelookup.employeetypetext
from tblappointmentdates
join tblemployeetypelookups on tblappointmentdates.employeetypeid = tblemployeetypelookups.employeetypeid" TableName="tblappointmentdates" Where="personnelid == #personnelid">
<WhereParameters>
<asp:ControlParameter ControlID="DropDownList1" Name="personnelid" PropertyName="SelectedValue" Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
thanks in advance.
Ok if I understood correctly what you should do is to pass the employeetypeid in a function and retrieve the text and bind that to control like this.
from
<asp:Label ID="Label1" runat="server" Text='<%# Bind("employeetypeid") %>'></asp:Label>
to
<asp:Label ID="Label1" runat="server" Text='<% #GetEmployeeName(Eval("employeetypeid"))%>' runat="server" />
so now GetEmployeeName is a server function you would write to fetch name from id.
protected string GetEmployeeName(int employeetypeid)
{
//What ever is the way to query and return from here
}
Also as side note I noticed you do naming like Label1 which is very poor practice.

clicking on link button in gridview does not show the details in detailsview

I have a grid view and a details view. In that grid view I have a link button column in the first column. When I click on the link button column it has to show the corresponding row values in the details view. I am using separate data sources for details view and grid view.
This is the grid view code:
<asp:GridView ID="GridView2" runat="server"
DataSourceID="SqlDataSourcegridview" Height="533px" Width="316px"
style="text-align: left" EnableCallBack="false"
AutoGenerateColumns="False" >
<Columns>
<asp:TemplateField ShowHeader="false">
<HeaderTemplate>
<asp:Label ID="lbl1" runat="server" Text="DCN"></asp:Label>
</HeaderTemplate>
<ItemTemplate>
<asp:LinkButton ID="lnkname" runat="server" SortExpression="DCN"
Text='<%#Eval("DCN") %>' CausesValidation="false"
CommandName='<%#Eval("DCN")%>' OnClick = "Link_buttonClick">
linkbutton
</asp:LinkButton>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="priority" HeaderText="priority"
SortExpression="priority" />
</Columns>
</asp:GridView>
Datasource for gridview:
<asp:SqlDataSource ID="SqlDataSourcegridview" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectDBString %>"
SelectCommand="SELECT * FROM [MASTERETMTABLE] WHERE ([DCN] = #DCN)">
<SelectParameters>
<asp:Parameter DefaultValue="BAT" Name="DCN" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
Details view:
<asp:Panel ID="paneldetails" runat="server" BackColor="#CCCCCC"
Visible="False" >
<asp:DetailsView ID="detailsvw" runat="server" AutoGenerateRows="False"
DataSourceID="SqlDataSourcedetailsview" Width="424px">
<Fields>
<asp:BoundField DataField="DCN" HeaderText="DCN" SortExpression="DCN" />
<asp:BoundField DataField="PRIORITY" HeaderText="PRIORITY"
SortExpression="PRIORITY" />
</Fields
</asp:DetailsView>
</asp:Panel>
and this is my datasource for details view
<asp:SqlDataSource ID="SqlDataSourcedetailsview" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectDBString %>"
SelectCommand="SELECT * FROM [MASTERETMTABLE] WHERE ([DCN] = #DCN)">
<SelectParameters>
<asp:ControlParameter Name="DCN" ControlID="GridView2"/>
</SelectParameters>
</asp:SqlDataSource>
This is the code behind file for the gridview page.
protected void Link_buttonClick(object sender, EventArgs e)
{
paneldetails.Visible = true;
detailsvw.Visible = true;
// do I need to add any thing at here
}
I am not able to get the data into details view here. When I click on any cell in the first column it shows the details view in panel.
How do I get the details view to display the data from the clicked row?
The easy way to implement Master-Details relationship is to add the DataKeyNames="DCN" (pertinent to your case) to the first GridView and refer to it as a Parameter in Details form: see the sample here: http://www.vkinfotek.com/detailsview/gridview-detailsview-master-detail-example.html

Passing parameter to sqldatasource that's bound to a dropdownlist in a gridview update

I have an editable gridview with many columns. Two of which are 100mPlot and SubPlot. SubPlot's are not unique (1A, 1B, 1C, and 1D) but 100mPlot + SubPlot make a unique set of values.
When a user clicks "Edit", they will see a dropdown list in the SubPlot column. This list needs to be based on what the value of 100mPlot is. So in order to display the correct values for SubPlot, I need to pass in a value from 100mPlot column as a parameter to the sqldatasource that would be bound to the SubPlot dropdownlist. How would I go about this?
<asp:BoundField DataField="100mPlot" HeaderText="100m plot"
SortExpression="100mPlot" ReadOnly="True" />
<asp:TemplateField HeaderText="SubPlot" SortExpression="SubPlot">
<EditItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="dsSubPlotNames"
DataTextField="SiteID" DataValueField="SiteID"
SelectedValue='<%# Bind("SiteID") %>'
AppendDataBoundItems="True">
<asp:ListItem Value=""></asp:ListItem>
</asp:DropDownList>
<asp:SqlDataSource ID="dsSubPlotNames" runat="server"
ConnectionString="<%$ ConnectionStrings:WERCMTX %>" SelectCommand="exec [339_PPM].usp_SubPlotNames_Select #100mPlotSiteID;">
<SelectParameters>
<asp:Parameter Name="100mPlotSiteID" />
</SelectParameters>
</asp:SqlDataSource>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label3" runat="server" Text='<%# Bind("SubPlot")%>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
As you can see, the parameter name "100mPlotSiteID" needs to be taken from 100mPlot column. I'm not sure how else to describe this anymore clearly, let me know if you have any questions. Thanks for your help.
EDIT with newly revised code. So close now!
<asp:TemplateField HeaderText="SubPlot" SortExpression="SubPlot">
<EditItemTemplate>
<asp:DropDownList ID="DropDownList1" runat="server"
DataSourceID="dsSubPlotNames"
DataTextField="SiteName" DataValueField="SiteID"
SelectedValue='<%# Bind("SiteID") %>'
>
</asp:DropDownList>
<asp:SqlDataSource ID="dsSubPlotNames" runat="server"
ConnectionString="<%$ ConnectionStrings:WERCMTX %>" SelectCommand='exec [339_PPM].usp_SubPlotNames_Select null, #100mPlotName;'
CancelSelectOnNullParameter="False">
<SelectParameters>
<asp:ControlParameter ControlID="GridView1" DefaultValue='<%# Eval("100mPlot") '
Name="100mPlotName" PropertyName="SelectedValue" />
</SelectParameters>
</asp:SqlDataSource>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label3" runat="server" Text='<%# Bind("SubPlot") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
Unfortunately, I get this error with the Eval("100mPlot"):
Databinding expressions are only supported on objects that have a DataBinding event. System.Web.UI.WebControls.ControlParameter does not have a DataBinding event.
You need to put a label and set the text property to '<%# Eval("100mPlot") %>' and use a control paremeter in dthe datasource.
If the label's id is "label1" (must be inside edit item template) then use this
<asp:ControlParameter ControlID="label1" PropertyName="Text" Name="100mPlotSiteID" />

Failed to load viewstate when trying to update/cancel on gridview?

Background
I have a GridView that builds a table using an ObjectDataSource. This source uses web services for both the select and update segments. Under the edit section, when clicked, has a DropDownList appear for the two columns that need to be editable. The DropDownLists both use separate ObjectDataSources storing WebServices that obtain the values meant to be stored in this DropDownList.
Currently working
At the moment, all of the above works. When I load the page, the table comes up with the proper data. When I click on the edit button, the two DropDownLists come up with the proper data stored in them from the WebService.
The Problem
When I select an option to update the DB or when I select cancel, the page throws an error and fails. I am not entirely sure why this happens, other than that it has to do with the binding not being handled correctly. I would like to know how to bind the values obtained from the DropDownList to be used when updating the database?
Below you will find what i have tried so far:
<asp:GridView ID="GridViewHolder"
runat="server"
AllowPaging="True"
AutoGenerateColumns="False"
BackColor="Transparent"
BorderColor="#999999"
BorderStyle="Ridge"
BorderWidth="3px"
CellPadding="4"
CellSpacing="2"
DataSourceID="MachineDataSet"
ForeColor="Black"
HeaderStyle-HorizontalAlign="Center"
HorizontalAlign="Center"
RowStyle-HorizontalAlign="Center" Width="574px"
OnRowUpdating="GridViewHolder_Updating"
OnRowCancelingEdit="GridViewHolder_Canceling"
OnRowUpdated="GridViewHolder_Updated"
OnRowEditing="GridViewHolder_Editing">
<RowStyle BackColor="Transparent" HorizontalAlign="Center" />
<Columns>
<asp:BoundField DataField="ID"
HeaderText="ID"
SortExpression="ID"
Visible="False" />
<asp:BoundField DataField="SiteName"
HeaderText="Site Name"
SortExpression="SiteName"
ReadOnly="true" />
<asp:BoundField DataField="Name"
HeaderText="Machine Name"
ReadOnly="true"
SortExpression="Name" />
<asp:TemplateField HeaderText="Machine Type" SortExpression="MachineType">
<EditItemTemplate>
<asp:ObjectDataSource ID="GetMachineType"
runat="server"
SelectMethod="GetMachineTypeList"
TypeName="Datamart.UI.Reporting.Web.FilteredReportInputsSvc.FilteredReportInputsService">
<SelectParameters>
<asp:Parameter Name="siteid" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:DropDownList ID="MachineTypeDropDown"
runat="server"
AppendDataBoundItems="True"
DataSourceID="GetMachineType"
DataTextField="Name"
DataValueField="ID"
Height="21px"
Width="217px">
<asp:ListItem Enabled="true"
Text="Select a Machine Type.">
</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1"
runat="server"
Text='<%# Bind("MachineType") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Machine Model" SortExpression="MachineModel">
<EditItemTemplate>
<asp:ObjectDataSource ID="GetMachineModel"
runat="server"
SelectMethod="GetMachineModelList"
TypeName="Datamart.UI.Reporting.Web.FilteredReportInputsSvc.FilteredReportInputsService">
<SelectParameters>
<asp:Parameter Name="siteid" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:DropDownList ID="MachineModelDropDown"
runat="server"
AppendDataBoundItems="True"
DataSourceID="GetMachineModel"
DataTextField="Name"
DataValueField="ID"
Height="21px"
Width="217px">
<asp:ListItem Enabled="true"
Text="Select a Machine Model."
Value="NULL">
</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2"
runat="server"
Text='<%# Bind("MachineModel") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:CommandField ButtonType="Button" ShowEditButton="True" />
</Columns>
<FooterStyle BackColor="Transparent" />
<PagerStyle BackColor="Transparent"
ForeColor="Black"
HorizontalAlign="Left" />
<SelectedRowStyle BackColor="Transparent"
Font-Bold="True"
ForeColor="White" />
<HeaderStyle BackColor="Black"
Font-Bold="True"
ForeColor="White"
HorizontalAlign="Center" />
</asp:GridView>
Where the problem seems to lie, is in this area below:
<asp:TemplateField HeaderText="Machine Type"
SortExpression="MachineType">
<EditItemTemplate>
<asp:ObjectDataSource ID="GetMachineType"
runat="server"
SelectMethod="GetMachineTypeList"
TypeName="Datamart.UI.Reporting.Web.FilteredReportInputsSvc.FilteredReportInputsService">
<SelectParameters>
<asp:Parameter Name="siteid" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:DropDownList ID="MachineTypeDropDown"
runat="server"
DataSourceID="GetMachineType"
DataTextField="Name"
DataValueField="ID"
Height="21px"
Width="217px"
AppendDataBoundItems="true">
<asp:ListItem Enabled="true"
Selected="True"
Text="Select a Machine Type.">
</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1"
runat="server"
Text='<%# Bind("MachineType") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Machine Model"
SortExpression="MachineModel">
<EditItemTemplate>
<asp:ObjectDataSource ID="GetMachineModel"
runat="server"
SelectMethod="GetMachineModelList"
<asp:TemplateField HeaderText="Machine Type" SortExpression="MachineType">
<EditItemTemplate>
<asp:ObjectDataSource ID="GetMachineType"
runat="server"
SelectMethod="GetMachineTypeList"
TypeName="Datamart.UI.Reporting.Web.FilteredReportInputsSvc.FilteredReportInputsService">
<SelectParameters>
<asp:Parameter Name="siteid" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:DropDownList ID="MachineTypeDropDown"
runat="server"
AppendDataBoundItems="True"
DataSourceID="GetMachineType"
DataTextField="Name"
DataValueField="ID"
Height="21px"
Width="217px">
<asp:ListItem Enabled="true"
Text="Select a Machine Type.">
</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label1"
runat="server"
Text='<%# Bind("MachineType") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Machine Model" SortExpression="MachineModel">
<EditItemTemplate>
<asp:ObjectDataSource ID="GetMachineModel"
runat="server"
SelectMethod="GetMachineModelList"
TypeName="Datamart.UI.Reporting.Web.FilteredReportInputsSvc.FilteredReportInputsService">
<SelectParameters>
<asp:Parameter Name="siteid" Type="String" />
</SelectParameters>
</asp:ObjectDataSource>
<asp:DropDownList ID="MachineModelDropDown"
runat="server"
AppendDataBoundItems="True"
DataSourceID="GetMachineModel"
DataTextField="Name"
DataValueField="ID"
Height="21px"
Width="217px">
<asp:ListItem Enabled="true"
Text="Select a Machine Model."
Value="NULL">
</asp:ListItem>
</asp:DropDownList>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2"
runat="server"
Text='<%# Bind("MachineModel") %>'>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
Updated for bounty
My overall problem is: using the gridview, I am unable to get my edit, update, cancel buttons to work. So what I would like to also know since I am throwing a bounty on this is: how can I get these events to work properly using ObjectDataSources?
I already know that the web services work properly, I just do not know how to load the necessary parameters with the right data-values from the table. Any help or suggestions are greatly appreciated.
Error thrown at the moment:
Failed to load viewstate. The control tree into
which viewstate is being loaded must match the
control tree that was used to save viewstate
during the previous request. For example, when
adding controls dynamically, the controls added
during a post-back must match the type and
position of the controls added during the
initial request.
I am unsure as to how to get the update and cancel events to fire correctly, so I have been trying to use the OnRow* event handlers, but none of these work or fire, even when I set up a break point on a method just to see if the event will fire.
Update2
So as requested here is what i have for the code behind dealing with the the events i had thought might fire, (note: i've tried this with almost all of the other events). When i would run a debugger attaching the page to an asp.net process and click on the update button, cancel button, or edit button i would expect the page to go to the breakpoint, however this does not happen.
Note: I also know that the code behind is most likely incorrect, but i didn't want to fix any of that until i knew which event would be the right one that fires for update and cancel buttons.
protected void GridViewHolder_Updating(object sender, GridViewUpdateEventArgs e)
{
int machineid;
string machineTypeid;
string machineModelid;
GridViewRow row = (GridViewRow)GridViewHolder.Rows[e.RowIndex];
Label id = (Label)row.FindControl("ID");
DropDownList mType1 = GridViewHolder.Rows[e.RowIndex].FindControl("MachineTypeDropDown") as DropDownList;
e.NewValues["MachineType"] = mType1.SelectedValue;
DropDownList mType = (DropDownList)row.FindControl("Machine_Type");
DropDownList mModel = (DropDownList)row.FindControl("Machine_Model");
machineid = Convert.ToInt32(id);
machineTypeid = mType.DataValueField.ToString();
machineModelid = mModel.DataValueField.ToString();
inputsService.UpdateMachineTypes(machineid, machineTypeid);
inputsService.UpdateMachineModels(machineid, machineModelid);
}
protected void GridViewHolder_Updated(object sender, GridViewUpdatedEventArgs e)
{
}
/// <summary>
/// Handles the Click event of the cancel button under edit in the gridview control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.Web.UI.WebControls.GridViewCancelEditEventArgs"/> instance containing the event data.</param>
protected void GridViewHolder_Canceling(object sender, GridViewCancelEditEventArgs e)
{
//reset the edit index
GridViewHolder.EditIndex = -1;
//Bind data to GridViewHolder
BindData();
}
protected void GridViewHolder_Editing(object sender, GridViewEditEventArgs e)
{
}
#endregion
#region Private Methods
private void BindData()
{
GridViewHolder.DataSource = Session["MachineTable"];
GridViewHolder.DataBind();
}
#endregion
Update 3
Okay you will find above the most recent attempt that i have done to try and get the update and cancel buttons to function properly in the gridview.
Any help or suggestions are greatly appreciated.
Thank you.
I would suspect that the ViewState error is being caused by code on the code-behind and is not being triggered by the GridView code you posted. Can your post the code-behind for your OnRow... methods and any Page_Load/Page_Init code?
Having said that, in order to get your updates to work for the DropDownList controls you'll need to add some code in the RowUpdating method. Here's a blog post by Peter Kellner, but the pertinent code is:
protected void GridViewIncomingUrls_RowUpdating(object sender, GridViewUpdateEventArgs e) {
DropDownList dropDownListUser = GridViewIncomingUrls.Rows[e.RowIndex].FindControl("MachineTypeDropDown") as DropDownList;
e.NewValues["MachineTypeID"] = dropDownListUser.SelectedValue;
}
Also, you may want to set the SelectedValue property of your dropwdowns, so that the previously selected value is pre-populated when the user hits the edit button:
<asp:DropDownList
ID="MachineModelDropDown"
SelectedValue='<%#Bind("MachineModelID") %>'
...
I've never seen an ObjectDataSource used inside a template - always controls explicitly populated / bound in ItemDataBound event of the grid.
Complex stuff like this, I would only use an ItemTemplate and then have all the controls (Label and DropDown in your case) inside that. Each would be toggled based on Grid.EditIndex > -1.
I would start by commenting out parts of the grid (like that whole piece with ObjectDataSource inside an EditTemplate) and see if that works.
If that dropdown / field is the culprit, then I'd re-work it to be populated inside Grid_ItemDataBound() event instead of inside markup.
One possible solution would be to enable the viewstate to false as so:
EnableViewState="false"
The links below will be of some help.
http://forums.asp.net/t/1159585.aspx/1
http://forums.asp.net/t/1295517.aspx/1

Gridview why all visible rows are set to dirty?

I'm using the BulkEditGridView control as discussed http://roohit.com/site/showArc.php?shid=bbb62, and it's perfect for my needs. The problem I'm having is that whenever I save, every visible row (I have paging enabled) gets updated. Stepping through the code I see that grid.DirtyRows.Count is equal to the number of items per page minus 1 when I click the save button.
I can't find where rows are set as dirty. Any suggestions where I can look?
My code-behind has only this:
using System;
using System.Web.UI.WebControls;
using System.Collections.Generic;
using System.Collections;
using System.Data.Common;
public partial class MSDS_MSDS_Admin_GridUpdate : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
gridMSDS.DataKeyNames = new String[] { "id" };
gridMSDS.DataBind();
}
}
}
EDIT: Here is the aspx code.
<%# Page Language="C#" MasterPageFile="~/MSDS/MSDS.master" AutoEventWireup="true" EnableEventValidation="false" CodeFile="GridUpdate.aspx.cs" Inherits="MSDS_MSDS_Admin_GridUpdate" Title="Untitled Page" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="cc1" %>
<%# Register Assembly="RealWorld.Grids" Namespace="RealWorld.Grids" TagPrefix="cc2" %>
<asp:Content ID="Content1" ContentPlaceHolderID="PageContent" runat="Server">
<br />
<asp:Button ID="btnSave" runat="server" Text="Save" Width="100%" />
<cc2:BulkEditGridView ID="gridMSDS" runat="server" AllowPaging="True" AllowSorting="True"
DataSourceID="sqlData" EnableInsert="False" InsertRowCount="1" PageSize="20"
SaveButtonID="btnSave" AutoGenerateColumns="False">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" InsertVisible="False" Visible="false"
ReadOnly="True" SortExpression="ID" />
<asp:BoundField DataField="ChemicalTitle" HeaderText="ChemicalTitle" SortExpression="ChemicalTitle" />
<asp:TemplateField HeaderText="SheetDate" SortExpression="SheetDate">
<EditItemTemplate>
<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("SheetDate") %>' Width="85px"></asp:TextBox>
<cc1:CalendarExtender ID="TextBox1_CalendarExtender" runat="server" Enabled="True"
TargetControlID="TextBox1">
</cc1:CalendarExtender>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label2" runat="server" Text='<%# Eval("SheetDate") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="Filename" HeaderText="Filename" SortExpression="Filename" />
<asp:BoundField DataField="Manufacturer" HeaderText="Manufacturer" SortExpression="Manufacturer" />
<asp:BoundField DataField="UsageDept" HeaderText="UsageDept" SortExpression="UsageDept" />
<asp:TemplateField HeaderText="Notes" SortExpression="Notes">
<EditItemTemplate>
<asp:TextBox ID="TextBox5" runat="server" Text='<%# Bind("Notes") %>' TextMode="MultiLine"></asp:TextBox>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label6" runat="server" Text='<%# Bind("Notes") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Status" SortExpression="Status">
<EditItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" DataSourceID="sqlStatus" DataTextField="DisplayValue"
DataValueField="Value" SelectedValue='<%# Bind("Status") %>'>
</asp:DropDownList>
<asp:SqlDataSource ID="sqlStatus" runat="server" ConnectionString="<%$ ConnectionStrings:NCLWebConnectionString %>"
SelectCommand="getOptionList" SelectCommandType="StoredProcedure">
<SelectParameters>
<asp:Parameter DefaultValue="msds_Status" Name="ListName" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
</EditItemTemplate>
<ItemTemplate>
<asp:DropDownList ID="ddlStatus" runat="server" DataSourceID="sqlStatus" disabled="true"
BackColor="White" DataTextField="DisplayValue" DataValueField="Value" SelectedValue='<%# Bind("Status") %>'>
</asp:DropDownList>
<asp:SqlDataSource ID="sqlStatus" runat="server" ConnectionString="<%$ ConnectionStrings:NCLWebConnectionString %>"
SelectCommand="getOptionList" SelectCommandType="StoredProcedure">
<SelectParameters>
<asp:Parameter DefaultValue="msds_Status" Name="ListName" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Health" SortExpression="Health">
<EditItemTemplate>
<center>
<asp:TextBox ID="TextBox2" runat="server" Style="text-align: center" Text='<%# Bind("Health") %>'
Width="25px"></asp:TextBox>
</center>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label3" runat="server" Text='<%# Bind("Health") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Fire" SortExpression="Fire">
<EditItemTemplate>
<center>
<asp:TextBox ID="TextBox3" runat="server" Text='<%# Bind("Fire") %>' Width="25px"></asp:TextBox></center>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label4" runat="server" Text='<%# Bind("Fire") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Reactivity" SortExpression="Reactivity">
<EditItemTemplate>
<center>
<asp:TextBox ID="TextBox4" runat="server" Text='<%# Bind("Reactivity") %>' Width="25px"></asp:TextBox></center>
</EditItemTemplate>
<ItemTemplate>
<asp:Label ID="Label5" runat="server" Text='<%# Bind("Reactivity") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="DateUpdated" HeaderText="DateUpdated" SortExpression="DateUpdated"
ReadOnly="True" />
<asp:BoundField DataField="UpdatedBy" ReadOnly="True" HeaderText="UpdatedBy" SortExpression="UpdatedBy" />
</Columns>
</cc2:BulkEditGridView>
<asp:SqlDataSource ID="sqlData" runat="server" ConnectionString="<%$ ConnectionStrings:NCLWebConnectionString %>"
SelectCommand="SELECT [ID], [ChemicalTitle], dbo.dateOnly([SheetDate]) As [SheetDate], [Filename], [Manufacturer], [UsageDept], [Notes], isnull([Status], 4) as [Status], [Health], [Fire], [Reactivity], [DateUpdated], [UpdatedBy] FROM [msds_Sheets] ORDER BY [ChemicalTitle]"
UpdateCommand="msds_UpdateSheet" UpdateCommandType="StoredProcedure">
<UpdateParameters>
<asp:Parameter Name="ID" Type="Int32" />
<asp:Parameter Name="ChemicalTitle" Type="String" />
<asp:Parameter Name="SheetDate" DbType="DateTime" />
<asp:Parameter Name="Filename" Type="String" />
<asp:Parameter Name="Manufacturer" Type="String" />
<asp:Parameter Name="UsageDept" Type="String" />
<asp:Parameter Name="Notes" Type="String" />
<asp:Parameter Name="Status" Type="Int16" />
<asp:Parameter Name="Health" Type="Int16" />
<asp:Parameter Name="Fire" Type="Int16" />
<asp:Parameter Name="Reactivity" Type="Int16" />
<asp:ProfileParameter Name="UpdatedBy" Type="String" PropertyName="Username" />
</UpdateParameters>
</asp:SqlDataSource>
</asp:Content>
Testing Procedure is as follows:
-Load the page.
-Edit something in the first row.
-Click save button.
The code you have posted looks fine. My test code is almost identical to yours, but I cannot produce the unwanted results you are seeing.
The most significant difference between your code and mine is that I don't have the code for your master page. My master page is the default page created by VS 2008. Other than that, the differences are in the SQL and the underlying database. Specifically, I am not using any stored procedures, and I have made reasonable assumptions about the data types involved: the ID is int, Status is smallint, SheetDate is Date, DateUpdated is DateTime, and everything else is varchar.
EDIT: Your SheetDate appears to be just the date portion of an underlying DateTime value from the database. The fact that your query transforms the underlying data value for display purposes is not relevant, because the grid view can't tell that it is getting a modified value. END OF EDIT
Here are a few suggestions for diagnosing the problem:
Test without master page, or with a
very simple dummy master page that is
guaranteed not to have scripts that
interact with the BulkEditGridView.
Since the ToolkitScriptManager is
apparently on your master page, you will
need to either move the script
manager control to the page itself,
or else temporarily get rid of the
CalendarExtender element, which
requires the script manager.
Temporarily replace the Status
template field with a bound data
field, to eliminate possibility of
interaction with the DropDownList.
The drop down list did not cause
problems in my tests, but there may
be subtle differences between your
code and mine.
If neither of these help, then a possible cause is a problem in your
version of the BulkEditGridView.
EDIT - Additional suggestions for diagnosis:
Based on examination of the source code for BulkEditGridView, it appears that the code is properly tracking which rows of the grid are "dirty". Therefore, the most likely cause of a spurious dirty row is that one or more controls in the grid are incorrectly detecting a change to their data content. You can detect this in the debugger, using the source code for BulkEditGridView, rather than the pre-compiled DLL.
Set a breakpoint at the start of HandleRowChanged, the event handler which detects changes in any cell of the grid. By examining the sender parameter of that object in the debugger, you can tell which controls in the grid are undergoing value changes. In particular, you will be able to tell which controls, if any, are incorrectly triggering a value change event.
Once you determine which control(s) are incorrectly reporting that their value has changed, you can focus on why this is happening.
END OF EDIT
Some other suggestions to improve the code are as follows. These will not solve the original problem, but will make the code cleaner:
In all of the template fields, remove the ItemTemplates. They can never be used, since the BulkEditGridView forces every row to be in the edit state.
In the code behind, the BindData()
call is not needed, since the source
data is specified in the declarative
markup, and therefore the grid view
control will automatically bind the
data.
I am not an expert in BulkEditGridView control, but this is what I found at Matt Dotson's blog entry
You may not be able to know that the row has been updated, unless you watch for the change explicitly. First, for each row add a change handler
protected override void InitializeRow(GridViewRow row, DataControlField[] fields)
{
base.InitializeRow(row, fields);
foreach (DataControlFieldCell cell in row.Cells)
{
if (cell.Controls.Count > 0)
{
AddChangedHandlers(cell.Controls);
}
}
}
You can use this snippet
private void AddChangedHandlers(ControlCollection controls)
{
foreach (Control ctrl in controls)
{
if (ctrl is TextBox)
{
((TextBox)ctrl).TextChanged += new EventHandler(this.HandleRowChanged);
}
else if (ctrl is CheckBox)
{
((CheckBox)ctrl).CheckedChanged += new EventHandler(this.HandleRowChanged);
}
else if (ctrl is DropDownList)
{
((DropDownList)ctrl).SelectedIndexChanged += new EventHandler(this.HandleRowChanged);
}
}
}
Then you define a dirty row list and add rows that needs to be updated there (in the event handler)
private List<int> dirtyRows = new List<int>();
void HandleRowChanged(object sender, EventArgs args)
{
GridViewRow row = ((Control) sender).NamingContainer as GridViewRow;
if (null != row && !dirtyRows.Contains(row.RowIndex))
{
dirtyRows.Add(row.RowIndex);
}
}
Finally, to commit changes, iterate through all the dirty rows and save changes
public void Save()
{
foreach (int row in dirtyRows)
{
this.UpdateRow(row, false);
}
dirtyRows.Clear();
}
And here is your ASPX code
<asp:Button runat="server" ID="SaveButton" Text="Save Data" />
<blog:BulkEditGridView runat="server" id="EditableGrid" DataSourceID="AdventureWorks" AutoGenerateColumns="False" DataKeyNames="LocationID" SaveButtonID="SaveButton" >
<Columns>
<asp:BoundField DataField="LocationID" HeaderText="LocationID" InsertVisible="False" ReadOnly="True" SortExpression="LocationID" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:BoundField DataField="Availability" HeaderText="Availability" SortExpression="Availability" />
<asp:BoundField DataField="CostRate" HeaderText="CostRate" SortExpression="CostRate" />
</Columns>
</blog:BulkEditGridView>

Categories