Link to home
Start Free TrialLog in
Avatar of acancel
acancelFlag for Afghanistan

asked on

Filter 1 DropDownList With Selection of Another DropDownList within a gridview

Hi All

I currently have two drop down lists in a gridview asp.net 2.0 and would like to filter the 2nd drop down with the selection of the first drop down. Thanks
Avatar of gregg1ep00
gregg1ep00

This may be a little tricky, because individual columns can't see each other's controls.  Are these two dropdowns in the same column?
Avatar of acancel

ASKER

no. One dropdown is asset_type (desktop or laptop), the other dropdown is justification (justifications grouped by desktops and laptops). I need when a user selects that their asset is a desktop, for the respective desktop justifications to display within the justification dropdown. Both these columns are in a gridview, the same gridview we were discussing the issue in
Ok.  This IS possible, but since they are in different columns, the controls can't see each other.  In other words, you're going to have something like this:

<asp:TemplateField HeaderText="Asset Type" SortExpression="asset_type">
   <ItemTemplate>
      <asp:Label id="AssetType" runat="server" Text='<%# Bind("asset_type") %>' />
   </ItemTemplate>
   <EditItemTemplate>
      <asp:DropDownList id="cboAssetType" runat="server" DataSourceId="dsAssetTypes" DataTextField="Name" DataValueField="Name" AutoPostBack="true" OnSelectedIndexChanged="cboAssetType_SelectedIndexChanged" />
      <asp:SqlDataSource id="dsAssetTypes" runat="server" ConnectionString="connectionString" SelectCommand="SELECT * FROM AssetTypes" />
   </EditItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Justification" SortExpression="justification">
   <ItemTemplate>
      <asp:Label id="Justification" runat="server" Text='<%# Bind("justification" ) %>' />
   </ItemTemplate>
   <EditItemTemplate>
      <asp:DropDownList id="cboJustification" runat="server" DataTextField="Name" DataValueField="Name" />
      <asp:SqlDataSource id="dsJustifications" runat="server" ConnectionString="connectionString" SelectCommand="SELECT * FROM Justifications WHERE justification = @justification">
            <SelectParameters>
                  <asp:Parameter Name="justification" Type="String"
            </SelectParameters>
      </asp:SqlDataSource>
   </EditItemTemplate>
</asp:TemplateField>

You'll notice that the DropDownList for justification does not have a SqlDataSource attached to it.  That's because its data bindings depend on the selected value of the asset_type DropDownList.  You'll need to handle the GridView's "RowDataBound" event and the "OnSelectedIndexChanged" event of the asset_type DropDownList.  Also, we're going to set AutoPostBack="true" for the asset_type DropDownList, so that when the user changes the value, you can re-bind your justification DropDownList and retrieve all justifications for that asset_type.

This is how the code would look in C# (I haven't ported it to VB yet):

' This is the GridView's RowDataBound handler
If e.Row.RowType = DataControlRowType.DataRow And e.Row.RowIndex = GridView1.EditIndex Then
        Dim cboAssetTypes As DropDownList = CType(e.Row.FindControl("cboAssetTypes"), DropDownList)
        Dim cboJustifications As DropDownList = CType(e.Row.FindControl("cboJustifications"), DropDownList)
        Dim dsJustifications As SqlDataSource = CType(e.Row.FindControl("dsJustifications"), SqlDataSource)
        Dim drv As DataRowView = CType(e.Row.DataItem, DataRowView)

        If sender <> cboAssetTypes Then
                cboAssetTypes.SelectedValue = drv("asset_type").ToString()
                If cboAssetTypes.SelectedValue.Length > 0 Then
                        dsJustifications.SelectParameters("asset_type").DefaultValue = cboAssetTypes.SelectedValue
                        cboJustifications.DataSource = dsJustifications.Select()
                        cboJustifications.DataBind()
                        cboJustifications.SelectedValue = drv("justification").ToString()
                End If
        End If
End If

' This is the cboAssetType DropDownList's SelectedIndexChanged handler
If GridView1.EditIndex > -1 Then
        Dim row As GridViewRow = GridView1.Rows(GridView1.EditIndex)
        Dim cboAssetTypes As DropDownList = CType(row.FindControl("cboAssetTypes"), DropDownList)
        Dim cboJustifications As DropDownList = CType(row.FindControl("cboJustifications"), DropDownList)
        Dim dsJustifications As SqlDataSource = CType(row.FindControl("dsJustifications"), SqlDataSource )
        dsJustifications.SelectParameters("asset_type").DefaultValue = cboAssetTypes.SelectedValue
        cboJustifications.DataSource = dsJustifications.Select( DataSourceSelectArguments.Empty )
        cboJustifications.DataBind()
End If


Hopefully I haven't made this too confusing.  But basically, you must do custom data binding on the filtered DropDownList (in this case, cboJustifications), because the two DropDownLists can't see each other (they are in different columns).

We will have to tweak these methods a little bit to work with inserting data, but this is the general idea.

Also, you're going to have to implement the DataGrid's OnUpdating handler:
        Dim cboAssetTypes As DropDownList = CType(row.FindControl("cboAssetTypes"), DropDownList)
        Dim cboJustifications As DropDownList = CType(row.FindControl("cboJustifications"), DropDownList)
        e.NewValues["asset_type"] = cboAssetTypes.SelectedValue
        e.NewValues["justification"] = cboJustifications.SelectedValue

Hope that helps!  Again, please excuse my VB syntax!  ;)
Oops, sorry, I DID port to VB as I was typing it!  Forgot to change that part of my post!
Just noticed another couple of mistakes.  In my OnUpdating handler at the bottom of my long post, these lines:
        e.NewValues["asset_type"] = cboAssetTypes.SelectedValue
        e.NewValues["justification"] = cboJustifications.SelectedValue

should be:
        e.NewValues("asset_type") = cboAssetTypes.SelectedValue
        e.NewValues("justification") = cboJustifications.SelectedValue

I told you my VB syntax sucks!!!  ;)
Another mistake... <blush>

In the RowDataBound handler above, change this line:
        cboJustifications.DataSource = dsJustifications.Select()

to this:
        cboJustifications.DataSource = dsJustifications.Select( DataSourceSelectArguments.Empty )
Avatar of acancel

ASKER

ok this is what I have, think I am inches away from getting this. I would like to see if we can figure this way out first before changing gears here. I created a data access layer for all the justifications adding a parameter for the computer_type. I was then able to successfully filter the data in the second dropdown when i hardcoded the computer type as the parameter within the datasource selecting class. The issue now is finding and calling asset type within the gridview. This is what I have

******this works*******
    Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        Dim sTarget As DropDownList = CType(FindControl("TargetComputerTypeDropDownlist"), DropDownList)

        e.InputParameters("computer_type") = "Desktop" 'sTarget.Selectedvalue
    End Sub


*******when i attempt to look to the selected value of starget, I get the following error*******
*******e.row is not part of this argument and starget is now null*******

System.NullReferenceException was unhandled by user code
  Message="Object reference not set to an instance of an object."
  Source="App_Web_rxmp6bur"
  StackTrace:
       at Assets_Targ_Edit.ObjectDataSource1_Selecting(Object sender, ObjectDataSourceSelectingEventArgs e) in C:\WebSites\Dev\BusinessUnits\Assets_Targ_Edit.aspx.vb:line 95
       at System.Web.UI.WebControls.ObjectDataSourceView.OnSelecting(ObjectDataSourceSelectingEventArgs e)
       at System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)
       at System.Web.UI.WebControls.ListControl.OnDataBinding(EventArgs e)
       at System.Web.UI.WebControls.ListControl.PerformSelect()
       at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()
       at System.Web.UI.Control.DataBindChildren()


It looks like all I need to do is to be able to get the value of the selection
Ok.  I was just looking at doing something like this with the SqlDataSource.

Are you setting the DataSourceID of your justification DropDownList to your ObjectDataSource?

Here, try this in your Selecting method:
-------------------
Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting
        If GridView1.EditIndex > -1 Then
                Dim row As GridViewRow = GridView1.Rows(GridView1.EditIndex)
                Dim sTarget As DropDownList = CType(row.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

                e.InputParameters("computer_type") = "Desktop" 'sTarget.Selectedvalue
        End If
End Sub
---------------------

The problem I'm running into is that on this line:
                Dim row As GridViewRow = GridView1.Rows(GridView1.EditIndex)
it's throwing an ArgumentOutOfRangeException, because the row hasn't been created yet.  See if you get the same behavior, and we'll go from there.

Greg
Avatar of acancel

ASKER

Actually we have to look at this from two angles right

1. On RowDataBound : Edit, we have to filter the justifications to that rows asset type, lets say Laptop. So for this step, is there a way to declare a global variable for assets that we previously capture for the enabling, disabling issue. Then i can just call that variable within the objectdatasource selecting event
2. Once the user is in the row, if they have a laptop then select desktop, a postback will occur, which may kick off step 1, if not, we would then have to re-set the objectdatasource for the justification field

does that make sense
I'm a little confused as to what you're saying in #1, but I completely agree with #2.

Hey, try this.

First, add a variable in your class called CurrentGridRow of type GridViewRow.

At the top of your RowDataBound handler, add this line:
        Me.CurrentGridRow = e.Row

In your SelectedIndexChanged handler for your asset_type combo, you'll have something like this:
        If GridView1.EditIndex > -1 Then
                Dim row As GridViewRow = GridView1.Rows(GridView1.EditIndex)
                Me.CurrentGridRow = row        '<--------------- ADD THIS LINE
                ...
        End If

In you ObjectDataSource_Selecting handler, it should look something like this:
Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting
        If GridView1.EditIndex > -1 And CurrentGridRow.RowType = DataControlRowType.DataRow Then
                Dim sTarget As DropDownList = CType(CurrentGridRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

                e.InputParameters("computer_type") = sTarget.Selectedvalue
        End If
End Sub
Avatar of acancel

ASKER

get the following error

Value cannot be null.
Parameter name: computer_type

in

Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        If GridView1.EditIndex > -1 And CurrentGridRow.RowType = DataControlRowType.DataRow Then
            Dim sTarget As DropDownList = CType(CurrentGridRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

            e.InputParameters("computer_type") = sTarget.SelectedValue <--------- Points to here
        End If

    End Sub

do I have to place quotes around the value? hmmmm
In your RowDataBound handler, make sure you're setting the value of the "TargetComputerTypeDropDownlist".  In other words:

If e.Row.RowType = DataControlRowType.DataRow And e.Row.RowIndex = GridView1.EditIndex Then
        Dim AssetTypeCbo As DropDownList = CType(e.Row.FindControl("TargetComputerTypeDropDownlist"), DropDownList)
        Dim JustificationCbo As DropDownList = CType(e.Row.FindControl("JustificationDropDownList"), DropDownList)
        Dim drv As DataRowView = CType(e.Row.DataItem, DataRowView)

        ' The next If stmt is because we don't want this to execute if the sender of the event is
        ' the dropdownlist.  In other words, we only want this to happen when data binding first
        ' takes place, not on postback of the DropDownList's SelectedIndexChanged event
        If sender <> AssetTypeCbo Then
                AssetTypeCbo.SelectedValue = drv("asset_type").ToString()

                ' Do we need to bind the justification here?  If so, include the following code.
                If AssetTypeCbo.SelectedValue.Length > 0 Then
                        JustificationCbo.DataBind()
                        JustificationCbo.SelectedValue = drv("justification").ToString()
                End If
        End If
End If
Avatar of acancel

ASKER

The if statement was actually not letting the code to run through, was not proving true. when i comment it out, we get the issue of not finding the control still
Not sure I'm following.  Explain?  Which if stmt?  :)
Avatar of acancel

ASKER

ok, this is what I ahve done, seems alot more simple. I added a global variable currentasset as string, then had the variable set within rowediting (manually set) to desktop. this populated to the parameter value in the objectdatesource selecting argument. Everything worked great. Now when I go to retrieve the value from the asset field, cell 3 it comes back empty. I could have sworn I had this working previoulsy to yesterdays enable issue. How can we get the global variable assigned on rowediting...it seems this is the last piece of the puzzle. Thanks for sticking through this

  Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        Dim sTargetValue As String = Me.CurrentAsset

        e.InputParameters("computer_type") = sTargetValue

    End Sub

    Protected Sub GridView1_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles GridView1.RowEditing

        Dim row As GridViewRow = GridView1.Rows(e.NewEditIndex)

        Dim sAsset As String = row.Cells(3).Text

        Me.CurrentAsset = sAsset

    End Sub
It doesn't work if you move the code in the RowEditing handler into the RowDataBound handler?

I've never really been a big fan of accessing grid data via the use of cells' text property, so I usually try to use the FindControl method of the row.  Unfortunately, the FindControl method doesn't work in the RowEditing handler, only in the RowDataBound handler.  The RowEditing event is fired before the row goes into edit mode, therefore the dropdownlist controls in the row have not been created.  The value you're getting by using the cells' text property in the RowEditing handler is the value of the label control in your <ItemTemplate> for that field.

You should be able to move your RowEditing code into the RowDataBound method and utilitize the DataItem property of e.Row.  So, you should be able to do this in RowDataBound:

Dim drv As DataRowView = CType(e.Row.DataItem, DataRowView)
Dim sAsset As String = drv("asset_type").ToString()
Me.CurrentAsset = sAsset


I've written a simple web page that works just like what you're trying to do (minus the stuff in your previous question).  It's in C#, but you could probably port it to VB pretty easily.  Maybe this will help.

ASPX code
--------------------------------
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="temp_Default" ValidateRequest="false" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
            <asp:GridView ID="GridView1"
            runat="server"
            AutoGenerateColumns="False"
            DataKeyNames="ProductID,VersionID,SectionID"
            DataSourceID="SqlDataSource1"
            OnRowDataBound="GridView1_RowDataBound" AutoGenerateEditButton="True">
                  <Columns>
                        <asp:TemplateField HeaderText="ProductID" SortExpression="ProductID">
                              <ItemTemplate>
                                    <asp:Label ID="ProductID" runat="server" Text='<%# Eval("ProductID") %>' />
                              </ItemTemplate>
                              <EditItemTemplate>
                                    <asp:DropDownList ID="cboProducts" runat="server" AutoPostBack="True" DataSourceID="dsProducts" DataTextField="Name" DataValueField="ProductID" OnSelectedIndexChanged="cboProducts_SelectedIndexChanged" />
                                    <asp:SqlDataSource ID="dsProducts" runat="server" ConnectionString="<%$ ConnectionStrings:connectorWeb %>" SelectCommand="SELECT [ProductID], [Name] FROM [Products]"></asp:SqlDataSource>
                              </EditItemTemplate>
                        </asp:TemplateField>
                        <asp:TemplateField HeaderText="VersionID" SortExpression="VersionID">
                              <ItemTemplate>
                                    <asp:Label ID="VersionID" runat="server" Text='<%# Eval("VersionID") %>' />
                              </ItemTemplate>
                              <EditItemTemplate>
                                    <asp:DropDownList ID="cboVersions" runat="server" DataSourceID="dsVersions" DataTextField="Name" DataValueField="VersionID" />
                                    <asp:SqlDataSource ID="dsVersions" runat="server" ConnectionString="<%$ ConnectionStrings:connectorWeb %>" SelectCommand="SELECT [ProductID], [VersionID], [Name] FROM [ProductVersions] WHERE ([ProductID] = @ProductID)" OnSelecting="dsVersions_Selecting">
                                          <SelectParameters>
                                                <asp:Parameter Name="ProductID" Type="Int32" />
                                          </SelectParameters>
                                    </asp:SqlDataSource>
                              </EditItemTemplate>
                        </asp:TemplateField>
                        <asp:BoundField DataField="SectionID" HeaderText="SectionID" InsertVisible="False" ReadOnly="True" SortExpression="SectionID" />
                        <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
                        <asp:BoundField DataField="LinkText" HeaderText="LinkText" SortExpression="LinkText" />
                        <asp:BoundField DataField="Title" HeaderText="Title" SortExpression="Title" />
                        <asp:BoundField DataField="Body" HeaderText="Body" SortExpression="Body" />
                        <asp:BoundField DataField="Keywords" HeaderText="Keywords" SortExpression="Keywords" />
                        <asp:BoundField DataField="StyleSheet" HeaderText="StyleSheet" SortExpression="StyleSheet" />
                        <asp:BoundField DataField="Flags" HeaderText="Flags" SortExpression="Flags" />
                        <asp:BoundField DataField="DateCreated" HeaderText="DateCreated" SortExpression="DateCreated" />
                        <asp:BoundField DataField="CreatedBy" HeaderText="CreatedBy" SortExpression="CreatedBy" />
                        <asp:BoundField DataField="DateModified" HeaderText="DateModified" SortExpression="DateModified" />
                        <asp:BoundField DataField="ModifiedBy" HeaderText="ModifiedBy" SortExpression="ModifiedBy" />
                  </Columns>
            </asp:GridView>
            <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:connectorWeb %>" SelectCommand="SELECT * FROM [ProductVersionSections]"></asp:SqlDataSource>
   
    </div>
    </form>
</body>
</html>


-----------------------------------
Code-behind
-----------------------------------
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class temp_Default : System.Web.UI.Page
{
      private GridViewRow m_CurrentRow;

      protected void Page_Load( object sender, EventArgs e )
      {

      }

      protected void GridView1_RowDataBound( object sender, GridViewRowEventArgs e )
      {
            m_CurrentRow = e.Row;

            if ( e.Row.RowType == DataControlRowType.DataRow && e.Row.RowIndex == GridView1.EditIndex )
            {
                  DropDownList cboProducts = e.Row.FindControl( "cboProducts" ) as DropDownList;
                  DropDownList cboVersions = e.Row.FindControl( "cboVersions" ) as DropDownList;
                  DataRowView drv = e.Row.DataItem as DataRowView;

                  if ( sender != cboProducts )
                  {
                        cboProducts.SelectedValue = drv["ProductID"].ToString();

                        if ( !string.IsNullOrEmpty( cboProducts.SelectedValue ) )
                        {
                              cboVersions.DataBind();

                              cboVersions.SelectedValue = drv["VersionID"].ToString();
                        }
                  }
            }
      }

      protected void cboProducts_SelectedIndexChanged( object sender, EventArgs e )
      {
            if ( GridView1.EditIndex > -1 )
            {
                  GridViewRow row = GridView1.Rows[GridView1.EditIndex];
                  m_CurrentRow = row;
                  DropDownList cboProducts = row.FindControl( "cboProducts" ) as DropDownList;
                  DropDownList cboVersions = row.FindControl( "cboVersions" ) as DropDownList;
                  cboVersions.DataBind();
            }
      }
      protected void dsVersions_Selecting( object sender, SqlDataSourceSelectingEventArgs e )
      {
            if ( GridView1.EditIndex > -1 && m_CurrentRow.RowType == DataControlRowType.DataRow )
            {
                  DropDownList cboProducts = m_CurrentRow.FindControl( "cboProducts" ) as DropDownList;

                  e.Command.Parameters["@ProductID"].Value = cboProducts.SelectedValue;
            }
            else
                  e.Cancel = true;
      }
}
Sorry, I should clarify...

It will not work if you simply move that code from your RowEditing handler to the RowDataBound handler.

You'll need to use the code I provided:
------------
Dim drv As DataRowView = CType(e.Row.DataItem, DataRowView)
Dim sAsset As String = drv("asset_type").ToString()
Me.CurrentAsset = sAsset
------------

You can make sure you're in "edit mode" and in the correct row by doing the first if stmt we discussed earlier:
-----------
If e.Row.RowType = DataControlRowType.DataRow And e.Row.RowIndex = GridView1.EditIndex Then
...
End If
-----------
Avatar of acancel

ASKER

will give it a try now
Avatar of acancel

ASKER

Ok this is the error I get

1st error is that parameter cannot be null. It seems it is looking for an initial default value. So if i popluate it with Desktop, it continues working (well have to come back to that one)

2nd error

System.ArgumentException was unhandled by user code
  Message="TargetComputerTypeDropDownlist is neither a DataColumn nor a DataRelation for table DefaultView."
  Source="System.Data"
  StackTrace:

****points to *****
    Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound

        Me.CurrentRow = e.Row

        If (e.Row.RowType = DataControlRowType.DataRow) And (e.Row.RowIndex = GridView1.EditIndex) Then
            Dim sTarget As DropDownList = CType(e.Row.FindControl("TargetComputerTypeDropDownlist"), DropDownList)
            Dim sJustification As DropDownList = CType(e.Row.FindControl("JustificationCommentDropDownlist"), DropDownList)
            Dim drv As Data.DataRowView = CType(e.Row.DataItem, Data.DataRowView)

            Dim oData As Data.DataRowView = CType(e.Row.DataItem, Data.DataRowView)
            Dim sAsset As String = oData("model_description").ToString()
            Dim sJustificationOther As TextBox = CType(e.Row.FindControl("TextBox1"), TextBox)

            If Not sender Is sTarget Then
                sTarget.SelectedValue = drv("TargetComputerTypeDropDownlist").ToString() <------------------------------------This is where the error is pointing to

                If sTarget.SelectedValue.Length > 0 Then
                    sJustification.DataBind()
                    sJustification.SelectedValue = drv("JustificationCommentDropDownlist").ToString()
                End If

            End If
Avatar of acancel

ASKER

why are we trying to assign  drv("label_target_asset_type").ToString() to sTarget.SelectedValue? Wouldn't that value already be there? Also, when I comment this line out just to let the code to continue, i then get the following error:

Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.

Source Error:


Line 161:            </ItemTemplate>
Line 162:            <EditItemTemplate >
Line 163:            <asp:DropDownList ID="JustificationCommentDropDownlist"  runat ="server"
Line 164:                DataSourceID = "ObjectDataSource1"
Line 165:                Datatextfield ="justification_comment"
 

Source File: C:\WebSites\Dev\BusinessUnits\Assets_Targ_Edit.aspx    Line: 163
As far as the error goes, change to this (I don't know what the column name is):
--------------------
sTarget.SelectedValue = drv("the name of the data-bound column for the targetComputerTypeDropDownlist").ToString()

AND also fix this too:

sJustification.SelectedValue = drv("the name of the data-bound column for the JustificationCommentDropDownlist").ToString()
--------------------

The reason we're doing this is because there is no mechanism to bind the DropDownList to a column in the ASPX code.  You'll notice there are no databinding statements in the ASPX code for either DropDownList.  So we bind it manually in the RowDataBound handler by setting the SelectedValue property once the DropDownList has been data-bound.

Does that make sense?
Again, to clarify:

When the GridView does its databinding, it goes through and creates each row of the grid.  For each result it finds from the SELECT of your SqlDataSource or ObjectDataSource control, it will create a row, then do databinding on that row.  Once the data binding is finished for the row, the RowDataBound event is fired.  That's where YOUR code comes in.

The DataItem property of the GridViewRow object is used ONLY in the RowDataBound handler.  It allows you to access the record from the database that corresponds with the GridView row that just finished databinding.

So if you set a breakpoint in your RowDataBound handler, the .NET framework has just finished performing any databinding you've set up in the ASPX part of your page.  If you want to do any custom databinding for controls, you do that here.  Which is why we have the lines:
      sTarget.SelectedValue = drv("target computer data column").ToString()
and
      sJustification.SelectedValue = drv("justification data column to bind to").ToString()

Hope that helps!
Avatar of acancel

ASKER

that does make sense, thanks

ok, fixed those, got a little further down, still getting the following error:

Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.

Source Error:


Line 161:            </ItemTemplate>
Line 162:            <EditItemTemplate >
Line 163:            <asp:DropDownList ID="JustificationCommentDropDownlist"  runat ="server"
Line 164:                DataSourceID = "ObjectDataSource1"
Line 165:                Datatextfield ="justification_comment"
Avatar of acancel

ASKER

actually I believe I fixed this issue by changeing Eval("justification_comment") to DataBinder.Eval(Container.DataItem, "justification_comment"). Getting another error now, believe it is because of the default value. Will post it now
Avatar of acancel

ASKER

yep, the issue is that if I dont have a value in the control parameter within the sqlobjectdatasource I get the following error:

Value cannot be null.
Parameter name: computer_type
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentNullException: Value cannot be null.
Parameter name: computer_type

Source Error:


Line 706:            this.Adapter.SelectCommand = this.CommandCollection[1];
Line 707:            if ((computer_type == null)) {
Line 708:                throw new System.ArgumentNullException("computer_type");
Line 709:            }
Line 710:            else {
 
Ok, I'm confused now.  Can you post the aspx code containing the GridView control (and contents) and any DataSource controls you have on your page, plus the entire VB code?

Thanks!
Somewhere you should be handling the object data source's OnSelecting event, and in there should be:

Dim sTarget As DropDownList = CType(Me.CurrentRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)
ObjectDataSourceThrowingTheError.SelectParameters("computer_type").DefaultValue = sTarget.SelectedValue

That will set the default value for the select stmt.
And that "computer_type" parameter should NOT be a ControlParameter (even though its value is coming from a control).  Just set it to a normal parameter:
<asp:ObjectDataSource ...>
  <SelectParameters>
     <asp:Parameter Name="computer_type" Type="String" />
  </SelectParameters>
</asp:ObjectDataSource>
Avatar of acancel

ASKER

This is what happend

1. When I view the page, everything is fine
2. Click edit
3. receive the error above
4. it looks like none of the vb is actually being kicked off. Bear in mind that in the objectdatasource there is a parameter for the computer_type (asset) and it looks like it is looking for this immediately. Not sure if i am making sense. Thanks

******This is the justification dropdownlist
            <asp:TemplateField HeaderText ="Justification Comment" ConvertEmptyStringToNull="False">
            <ItemTemplate >
               <asp:label ID="label_justification_comments" text='<%# Eval("justification_comment") %> ' runat ="server" />
            </ItemTemplate>
            <EditItemTemplate >
            <asp:DropDownList ID="JustificationCommentDropDownlist"  runat ="server"
                DataSourceID = "ObjectDataSource1"
                Datatextfield ="justification_comment"
                DataValueField ="justification_comment"
                SelectedValue= '<%#  DataBinder.Eval(Container.DataItem, "justification_comment") %>'  >
            </asp:DropDownList>
            </EditItemTemplate>          
            </asp:TemplateField>

******* here is the vb code

Partial Class Assets_Targ_Edit
    Inherits System.Web.UI.Page
    Dim CurrentAsset
    Dim CurrentRow As GridViewRow

    Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) _
            Handles Me.Load

        'capture current user name
        userid.Text = Master.UserID
        userid2.Text = Master.UserID

        'capture comm id
        Me.CommTextBox.Text = Request.QueryString("comm")

        'check the user to see if they have verified the units yet
        Checkuser()

    End Sub

    Protected Sub ButtonSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButtonSubmit.Click
        Dim strConn As Data.SqlClient.SqlConnection = New Data.SqlClient.SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("PCRefreshConnectionString").ConnectionString)
        strConn.Open()
        Dim sql As String
        sql = "UPDATE ct_asset_target_signoff SET[user_okay] = 'Y', [user_last_change_date] = '" & Now() & "', [user_last_change_user]='" & Me.userid.Text & "' WHERE [target_username] = '" & Me.userid.Text & "'"
        Dim Cmd As Data.SqlClient.SqlCommand = New Data.SqlClient.SqlCommand(sql, strConn)

        Cmd.CommandText = sql
        Cmd.ExecuteNonQuery()
        strConn.Close()
    End Sub

    Private Sub Checkuser()
        Dim oCmd As Data.SqlClient.SqlCommand
        Dim oDR As Data.SqlClient.SqlDataReader
        Dim strSQL As String
        Dim strConn As String

        strConn = ConnectStringBuild()

        strSQL = "SELECT * FROM [ct_asset_target_signoff] WHERE [target_username] ='" & Me.userid.Text & "' AND [user_okay] = 'y'"

        Try
            oCmd = New Data.SqlClient.SqlCommand
            With oCmd
                .Connection = New Data.SqlClient.SqlConnection(strConn)
                .Connection.Open()
                .CommandText = strSQL
                oDR = .ExecuteReader
            End With

            Do While oDR.Read
                Me.GridView1.Enabled = False
            Loop
            oDR.Close()

        Catch ex As Exception


        End Try
    End Sub

    Private Function ConnectStringBuild() As String
        Dim strConn As String

        strConn = "Data Source=SVDATAISEC2;Initial Catalog=PCRefresh;Integrated Security=True"

        Return strConn
    End Function

    Protected Sub GridView1_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound

        Me.CurrentRow = e.Row

        If (e.Row.RowType = DataControlRowType.DataRow) And (e.Row.RowIndex = GridView1.EditIndex) Then
            Dim sTarget As DropDownList = CType(e.Row.FindControl("TargetComputerTypeDropDownlist"), DropDownList)
            Dim sJustification As DropDownList = CType(e.Row.FindControl("JustificationCommentDropDownlist"), DropDownList)
            Dim drv As Data.DataRowView = CType(e.Row.DataItem, Data.DataRowView)

            Dim oData As Data.DataRowView = CType(e.Row.DataItem, Data.DataRowView)
            Dim sAsset As String = oData("model_description").ToString()
            Dim sJustificationOther As TextBox = CType(e.Row.FindControl("TextBox1"), TextBox)

            If Not sender Is sTarget Then
                sTarget.SelectedValue = drv("target_computer_type").ToString()

                If sTarget.SelectedValue.Length > 0 Then
                    sJustification.DataBind()
                    sJustification.SelectedValue = drv("justification_comment").ToString()
                End If

            End If

            'keep other justification comment control enabled to false until "Other" is selected in the justification column
            sJustificationOther.Enabled = False

            'if the asset type is a desktop, disable the target computer control, as well as the justification control
            If sAsset = "Desktop" Then
                sTarget.Enabled = False
                sJustification.Enabled = False
            End If

        End If
    End Sub

    Protected Sub TargetComputerTypeDropDownlist_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)

        If GridView1.EditIndex > -1 Then
            Dim row As GridViewRow = GridView1.Rows(GridView1.EditIndex)
            Me.CurrentRow = row
        End If

    End Sub

    Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        If GridView1.EditIndex > -1 And CurrentRow.RowType = DataControlRowType.DataRow Then
            Dim sTarget As DropDownList = CType(CurrentRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

            e.InputParameters("computer_type") = sTarget.SelectedValue
        End If

    End Sub
End Class


******This is the objectdatasource that is tied to the justification dropdownlist

                <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
                    DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetDataByComputer_type" TypeName="PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter"
                    UpdateMethod="Update">
                    <DeleteParameters>
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </DeleteParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </UpdateParameters>
                    <InsertParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                    </InsertParameters>
                    <SelectParameters>
                        <asp:Parameter Name="computer_type"
                            Type="String" />
                    </SelectParameters>
                </asp:ObjectDataSource>
Ok, I just learned something.  I had no idea that you could bind the SelectedValue property in the DropDownList in the ASPX.

I'm not doing that in my page, which is why I'm doing a lot of this stuff by hand.  I'm testing some stuff, I'll post my results.  :)
Can you add the OnSelecting handler in this ObjectDataSource definition and try it?

Let me know your results!  We're gonna get this!!!  ;)

******This is the objectdatasource that is tied to the justification dropdownlist

                <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
                    DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetDataByComputer_type" TypeName="PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter"
                    UpdateMethod="Update">
                    <DeleteParameters>
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </DeleteParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </UpdateParameters>
                    <InsertParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                    </InsertParameters>
                    <SelectParameters>
                        <asp:Parameter Name="computer_type"
                            Type="String" />
                    </SelectParameters>
                </asp:ObjectDataSource>
Avatar of acancel

ASKER

yes you can, glad you are as pumped as I am. i myself have learned alot throughout these ordeals. They do say that success is a poor teacher.

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
                    DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetDataByComputer_type" TypeName="PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter"
                    UpdateMethod="Update" OnSelecting= <----------------------------------------
Did you add the handler to the ObjectDataSource and try it yet?
------------
<asp:ObjectDataSource ID="ObjectDataSource1" ... OnSelecting="ObjectDataSource1_Selecting">
...
</asp:ObjectDataSource>
------------
and in code...
------------
Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        If GridView1.EditIndex > -1 And CurrentRow.RowType = DataControlRowType.DataRow Then
            Dim sTarget As DropDownList = CType(CurrentRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

            e.InputParameters("computer_type") = sTarget.SelectedValue
        End If

    End Sub
End Class
------------
Avatar of acancel

ASKER

yes, this is what i tried...it still failed...am trying something right now

                <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
                    DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetJustifications" TypeName="PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter"
                    UpdateMethod="Update" OnSelecting="ObjectDataSource1_Selecting">
                    <DeleteParameters>
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </DeleteParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </UpdateParameters>
                    <InsertParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                    </InsertParameters>
                </asp:ObjectDataSource>

***** Selecting

    Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        If GridView1.EditIndex > -1 And CurrentRow.RowType = DataControlRowType.DataRow Then

            Dim sTarget As DropDownList = CType(CurrentRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

            e.InputParameters("computer_type") = sTarget.SelectedValue
        End If

    End Sub
Avatar of acancel

ASKER

sorry pasted wrong datasource...was trying something out. If I set the datasource to the previous pasted one, all of the code starts to run, get all the way through to the databind then it fails because it does not find a computer_type parameter. Therefore as indicated below it seems the parameter for computer_type is being called immediately before any vb code runs, and since it has a default value of null, it fails. Perhaps we need to configure the datasource to all justifications then rebind the filter adapter to that datasource

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
                    DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetDataByComputer_type" TypeName="PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter"
                    UpdateMethod="Update">
                    <DeleteParameters>
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </DeleteParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </UpdateParameters>
                    <InsertParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                    </InsertParameters>
                    <SelectParameters>
                        <asp:Parameter Name="computer_type" <--------------------------------------------------- It seems this is what is null
                            Type="String" />
                    </SelectParameters>
                </asp:ObjectDataSource>
Ok, in your justification dropdownlist, can you try removing the SelectedValue databinding statement?

If that doesn't work, then let's try what you suggested.  Or have you tried it yet?  Any luck?
Avatar of acancel

ASKER

Ok this is what I did, seems to may be working.

1. Set the objectdatasource to retrieve all justifications

                <asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
                    DeleteMethod="Delete" InsertMethod="Insert" OldValuesParameterFormatString="original_{0}"
                    SelectMethod="GetJustifications" TypeName="PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter"
                    UpdateMethod="Update" OnSelecting="ObjectDataSource1_Selecting">
                    <DeleteParameters>
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </DeleteParameters>
                    <UpdateParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                        <asp:Parameter Name="Original_justification_id" Type="Int32" />
                    </UpdateParameters>
                    <InsertParameters>
                        <asp:Parameter Name="justification_comment" Type="String" />
                        <asp:Parameter Name="computer_type" Type="String" />
                    </InsertParameters>
                </asp:ObjectDataSource>

2. Add some vb code
                If sTarget.SelectedValue.Length > 0 Then
                    Dim justAdapter As New PCRefreshTableAdapters.ct_asset_target_justificationTableAdapter
                    Dim just As PCRefresh.ct_asset_target_justificationDataTable
                    just = justAdapter.GetDataByComputer_type(sTarget.SelectedValue)

                    sJustification.DataSource = just
                    sJustification.DataBind()
                    sJustification.SelectedValue = drv("justification_comment").ToString()
                End If

3. Get to sJustification.DataBind then get the following error:

Both DataSource and DataSourceID are defined on 'JustificationCommentDropDownlist'.  Remove one definition

Any ideas? am doing some research now
Avatar of acancel

ASKER

This is the control aspx code again

<asp:TemplateField HeaderText ="Justification Comment" ConvertEmptyStringToNull="False">
            <ItemTemplate >
               <asp:label ID="label_justification_comments" text='<%# Bind("justification_comment") %> ' runat ="server" />
            </ItemTemplate>
            <EditItemTemplate >
            <asp:DropDownList ID="JustificationCommentDropDownlist"  runat ="server"
                DataSourceID = "ObjectDataSource1"
                Datatextfield ="justification_comment"
                DataValueField ="justification_comment"
                SelectedValue= '<%#  DataBinder.Eval(Container.DataItem, "justification_comment") %>'  >
            </asp:DropDownList>
            </EditItemTemplate>          
            </asp:TemplateField>
Yeah, before you do the sJustification.DataBind(), add this line:

sJustification.DataSourceID = ""

That should fix the problem
If none of this works, then we can try to just scrap the DataSource controls and do our own custom data binding.  I find that in situations like this, it's easier for you to control the databinding on your own.

Let me know if it works.  My biggest concern is that it will work for updates and not for inserts.
Avatar of acancel

ASKER

ok that worked but when I hit update (without changing any of the values) it removed the data in both the target and justification fields.... (one step forward, two back...the story of IT)
Avatar of acancel

ASKER

fixed the target field, had Eval as oppose to Bind....However how do I reflect that change within the justification column, DataBinder.Eval(Container.DataItem, "justification_comment") wont let me change Eval to Bind
Avatar of acancel

ASKER

well sir, i am out here for the night. we shall pick it up in the morning
You should just be able to scrap the DataBinder syntax and simply use Bind("justification_comment")

Does that not work?
Avatar of acancel

ASKER

good morning

if I reset it to Bind(...., I get the following error:

Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control
Avatar of acancel

ASKER

ok, i removed the selected value from the control and updated the value in rowupdating

    Protected Sub GridView1_RowUpdating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewUpdateEventArgs) Handles GridView1.RowUpdating

        Dim row As GridViewRow = GridView1.Rows(GridView1.EditIndex)
        Dim sJustification As String = CType(row.FindControl("JustificationCommentDropDownlist"), DropDownList).SelectedValue

        e.NewValues("justification_comment") = sJustification
        e.Cancel = False
    End Sub

going to continue testing
That *should* help things move along.  I wish Microsoft would rework the DropDownList control to make databinding a little easier.  Now that I think about it, the error message you got above ("Databinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control") is the reason I've never gotten the DropDownList control to bind to a datasource using just the ASPX stuff (I hardly ever use the DataBinder syntax).

Anyway, let me know where you're at in regards to your testing.  Like I said, we can always do custom data binding and get it to work exactly how we want, it just requires a bit more code.
Avatar of acancel

ASKER

ok, making good headway, however when I hit edit on the second record, I get the follownig error

    Protected Sub ObjectDataSource1_Selecting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles ObjectDataSource1.Selecting

        If GridView1.EditIndex > -1 And CurrentRow.RowType = DataControlRowType.DataRow Then

            Dim sTarget As DropDownList = CType(CurrentRow.FindControl("TargetComputerTypeDropDownlist"), DropDownList)

            e.InputParameters("computer_type") = sTarget.SelectedValue <------------------------------- [Object reference not set to an instance of an object]
        End If

    End Sub
hm...  I get the same error on the page I made.  Testing now, I'll post results.
ASKER CERTIFIED SOLUTION
Avatar of gregg1ep00
gregg1ep00

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of acancel

ASKER

Ok, actually set it as

If (GridView1.EditIndex > -1) And (CurrentRow <> null) And (CurrentRow.RowIndex = GridView1.EditIndex)

that worked....well Gregg, look like we are golden...just need to add some logic to this such as if more than 1 pc, enable/disable, etc. If i have any issues with that i will let you know as well. Who knows my days out, you could have racked up 1,000s of points....Thanks for all your help
hehe  ;)

No problem!  Glad to help.  Good luck with your project!