I just learned something new and wanted to share. You have an asp.net GridView and in that GridView you have a Point of Contact column that shows the primary point of contact. In view mode you want to see the contacts Name, but in edit mode you want a DropDownList with all contacts for a given system, so that you can assign a new primary point of contact. A point of contact can be removed from the system, but can still be listed as the primary until he is replaced.
So you bind the SelectedValue of the DropDownList to the Id of the primary contact stored for that system. What happens when that contact is removed from the system? The DropDownList throws an error because the SelectedValue that you are binding doesn’t exist in the data source.
There are a couple of ways to fix this problem. First, the stored procedure can be changed to check for this condition and union the contacts with the old primary contact. Second, you can pass the contact Id from the GridView to the ObjectDataSource of the DropDownList that is inside the EditItemTemplate of the GridView. Lets say for the sake of argument that you don’t have access to the stored procedures, so you must do this union in code.
Here is the code I used to solve this problem.
First up is the GridView code from the ascx file. Notice a few things. First, the GridView is using the OnRowCreated event. Second, the SelectedValue of the DropDownList is being bound to the contactId of the GridView’s data source. The ObjectDataSource for the DropDownList has two SelectParameters, one for the contactId and one for systemId. There is also a RequiredFieldValidator to make sure the DropDownList doesn’t have a value of -1 selected. In the database -1 is an invalid index. This is important later while getting the data for the DropDownList.
<asp:GridView ID="GridViewVehicles" runat="server"
OnRowCreated="GridViewVehicles_RowCreated"
DataSourceID="ObjectDataSourceMain">
<Columns>
<asp:TemplateField HeaderText="Point of Contact">
<ItemTemplate>
<asp:Literal ID="LitPoc" runat="server" Text='<%# Eval("ContactPoc") %>'/>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="DropDownListPoc" runat="server"
DataSourceID="ObjectDataSourcePoc" DataTextField="Name" DataValueField="Id"
SelectedValue='<%# Bind("ContactIdPoc") %>'/>
<asp:ObjectDataSource ID="ObjectDataSourcePoc" runat="server"
TypeName="Bll.VehicleControlBll"
SelectMethod="GetRolesAndCurrentContactBySystemAndContact">
<SelectParameters>
<asp:Parameter Name="contactId" Type="Int32"/>
<asp:Parameter Name="systemId" Type="Int32"/>
</SelectParameters>
</asp:ObjectDataSource>
<asp:RequiredFieldValidator ID="ValidatorPoc" runat="server"
ErrorMessage="Not a valid selection." ControlToValidate="DropDownListPoc"
InitialValue="-1" Display="Dynamic" SetFocusOnError="True"/>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Now on to the C# code. In the RowCreated event, check to make sure this is a DataRow and not a header or footer row. Make sure the data for this row isn’t null, and then set the select parameters to that data item’s values. Now the ObjectDataSource has the correct values for this row.
The DropDownList’s ObjectDataSource is used next, and the following code shows the methods used to populate that. First the contacts are retrieved from the DAL for the given system, and then that List object is searched for the passed in contactId, if it’s not found then another DAL call is made to get that contact’s object. The name gets a “*” attached to signify this contact is no longer a POC for this system. Then a new contact is created with an Id of -1 and a name of “Pick Contact” and inserted at the beginning of the List. So now the List object passed to the ObjectDataSource holds an invalid value incase no nothing had been selected before (Ex. creating a new system), holds all the contacts for a system and in case the already assigned primary contact was removed, that contact is added to the list as well.
protected void GridViewVehicles_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType != DataControlRowType.DataRow) return;
VehicleDetails vehicle = e.Row.DataItem as VehicleDetails;
if (vehicle == null) return;
ObjectDataSource odsPoc = e.Row.FindControl("ObjectDataSourcePoc") as ObjectDataSource;
if (odsPoc != null)
{
odsPoc.SelectParameters["contactId"].DefaultValue = vehicle.ContactIdPoc;
odsPoc.SelectParameters["systemId"].DefaultValue = vehicle.SystemId;
}
}
public List<ContactDetails> GetRolesAndCurrentContactBySystemAndContact(int contactId, int systemId)
{
List<ContactDetails> contacts = AppendCurrentContact(GetRolesBySystem(systemId), contactId);
ContactDetails pickA = new ContactDetails();
pickA.Id = -1;
pickA.Name = "Pick Contact";
contacts.Insert(0, pickA);
return contacts;
}
private List<ContactDetails> AppendCurrentContact(List<ContactDetails> contacts, int contactId)
{
ContactDetails contact = contacts.Find(delegate(ContactDetails details)
{ return details.Id == contactId; });
if (contact == null)
{
ContactDetails newContact = VehicleControlDal.GetContactById(contactId);
if (newContact != null)
{
newContact.Name = newContact.Name + "*";
contacts.Add(newContact);
}
}
return contacts;
}