Question

I have two cascading dropdown lists I'm attempting to bind to two separate SqlDataSources each.

These dropdownlists exist in a FormView's EditItemTemplate. Inside the EditItemTemplate two sqldatasource controls exist that populate the department and the jobname. The DeptID and the JobID are the primary keys in those tables. This creates the "cascading effect" between departments and jobs. When a department is selected, only the jobs associated with that department appear.

This piece is working properly.

<asp:FormView ID="frmProfile" runat="server" DataSourceID="sqlDSProfile" 
    DataKeyNames="EUID" style="margin-top: 0px">
    <EditItemTemplate>
        <asp:DropDownList ID="ddlDepartments" runat="server" Width="135px"
            DataSourceID="sqlDSDepartments" 
            DataTextField="Department" 
            DataValueField="DeptID" AutoPostBack="True" 
            SelectedValue='<%# Bind("CurrentDeptID") %>' 
            AppendDataBoundItems="true" >
                <asp:ListItem></asp:ListItem>
        </asp:DropDownList>

        <asp:DropDownList ID="ddlJobNames" runat="server" Width="185px"
            DataSourceID="sqlDSJobs" DataTextField="JobName" DataValueField="JobID" 
            SelectedValue='<%# Bind("CurrentJobID") %>' 
            AppendDataBoundItems="true" >
                <asp:ListItem></asp:ListItem>
        </asp:DropDownList>

        <asp:SqlDataSource ID="sqlDSDepartments" runat="server" 
            ConnectionString="<%$ ConnectionStrings:JobsDB %>" 
            SelectCommand="SELECT tblDepartments.DeptID, 
                                  tblDepartments.Department 
                           FROM tblDepartments" />

        <asp:SqlDataSource ID="sqlDSJobs" runat="server" 
            ConnectionString="<%$ ConnectionStrings:JobsDB %>" 
            SelectCommand="SELECT tblJobs.JobID, tblJobs.JobName FROM tblJobs
                           INNER JOIN tblDeptsJobs ON tblDeptsJobs.JobID = tblJobs.JobID
                           WHERE tblDeptsJobs.DeptID = @DeptID" >
            <SelectParameters>
                <asp:ControlParameter ControlID="ddlDepartments" Name="DeptID" 
                    PropertyName="SelectedValue" />
            </SelectParameters>
        </asp:SqlDataSource>
    </EditItemTemplate>
</asp:FormView>

Outside the formview the SqlDataSource exists that binds all of the information to the Employee table in an update statement. I'm leaving all of the other information in this SqlDataSource even though it's been omitted from the FormView above.

<asp:SqlDataSource ID="sqlDSProfile" runat="server" 
    ConnectionString="<%$ ConnectionStrings:JobsDB %>" 
    SelectCommand="SELECT tblEmployee.EUID, 
                tblEmployee.DateHired, 
                tblEmployee.LastName, 
                tblEmployee.HiredLastName, 
                tblEmployee.FirstName, 
                tblEmployee.Role, 
                tblEmployee.JobGrade, 
                tblEmployee.CurrentDeptID, 
                tblDepartments.Department, 
                tblDepartments.DeptID, 
                tblEmployee.CurrentJobID, 
                tblJobs.JobName, 
                tblJobs.JobID, 
                tblEmployee.CurrentShift, 
                tblEmployee.JobDate, 
                tblEmployee.IsDisplaced, 
                tblEmployee.EligibilityDate 
            FROM tblEmployee 
                LEFT OUTER JOIN tblDepartments ON tblEmployee.CurrentDeptID = tblDepartments.DeptID 
                EFT OUTER JOIN tblJobs ON tblEmployee.CurrentJobID = tblJobs.JobID 
            WHERE (tblEmployee.EUID = @EUID)"
    UpdateCommand="UPDATE [tblEmployee] 
                SET [tblEmployee].[DateHired] = @DateHired, 
                    [tblEmployee].[LastName] = @LastName, 
                    [tblEmployee].[HiredLastName] = @HiredLastName, 
                    [tblEmployee].[FirstName] = @FirstName, 
                    [tblEmployee].[Role] = @Role, 
                    [tblEmployee].[JobGrade] = @JobGrade, 
                    [tblEmployee].[CurrentDeptID] = @CurrentDeptID, 
                    [tblEmployee].[CurrentJobID] = @CurrentJobID, 
                    [tblEmployee].[CurrentShift] = @CurrentShift, 
                    [tblEmployee].[JobDate] = @JobDate, 
                    [tblEmployee].[IsDisplaced] = @IsDisplaced, 
                    [tblEmployee].[EligibilityDate] = @EligibilityDate 
                WHERE [tblEmployee].[EUID] = @EUID"
                    ProviderName="System.Data.SqlClient">
    <SelectParameters>
        <asp:SessionParameter Name="EUID" SessionField="sProfileEUID" DbType="String" />
    </SelectParameters>
    <UpdateParameters>
        <asp:Parameter Name="DateHired" DbType="Date" />
        <asp:Parameter Name="LastName" DbType="String" />
        <asp:Parameter Name="HiredLastName" DbType="String" />
        <asp:Parameter Name="FirstName" DbType="String" />
        <asp:Parameter Name="Role" DbType="String" />
        <asp:Parameter Name="JobGrade" DbType="Byte" />
        <asp:Parameter Name="CurrentDeptID" DbType="Int32" />
        <asp:Parameter Name="CurrentJobID" DbType="Int32" />
        <asp:Parameter Name="CurrentShift" DbType="Int32" />
        <asp:Parameter Name="JobDate" DbType="Date" />
        <asp:Parameter Name="IsDisplaced" DbType="Boolean"/>
        <asp:Parameter Name="EligibilityDate" DbType="Date"/>
        <asp:SessionParameter Name="EUID" SessionField="sProfileEUID" DbType="String" />
    </UpdateParameters>
</asp:SqlDataSource>

The only pieces I can't figure out how to bind are the Departments and the Jobs. Everything else is working. I've tried using the following code in the DropDownList controls...

SelectedValue='<%# Bind("CurrentDeptID") %>'
SelectedValue='<%# Bind("CurrentJobID") %>'

...but these result in errors.

Summary

When the user clicks edit, I need the values in the two dropdownboxes to pull their selectedvalue from the main sqlDSProfile data source, but I need them to be updatable. I've gotten it to the point where I can update and bind the job that an associate belongs to, but because the dropdownlists cascade, when I attempt to change the department the AutoPostBack breaks the binding between sqlDSProfile - CurrentJobID and ddlJobs.

Update

I added tblEmployee.CurrentDeptID and tblEmployee.CurrentJobID to the select statement, and added Bind() statements to the DropDownList controls.

SelectedValue='<%# Bind("CurrentDeptID") %>' 
SelectedValue='<%# Bind("CurrentJobID") %>' 

The two DropDownLists are now populated with accurate information pulled from the Employee table, showing the department and job that the employee belongs to.

The two DropDownLists are also populated by the two SqlDataSources inside the FormView, giving me options for changing the department and changing the job.

When I change the Job, it works and the employees job is updated.

When I change the Department, it breaks saying DataBinding methods such as Eval(), XPath(), and Bind() can only be used in the context of a databound control.

Close to Done

I removed the data binding from ddlJobs and coded that in the background.

Protected Sub frmProfile_ItemUpdating(sender As Object, e As System.Web.UI.WebControls.FormViewUpdateEventArgs) Handles frmProfile.ItemUpdating
    If frmProfile.CurrentMode = FormViewMode.Edit Then
        e.NewValues("CurrentJobID") = DirectCast(DirectCast(sender, FormView).FindControl("ddlJobs"), DropDownList).SelectedValue
    End If
End Sub

The only piece that's left is building the code for when the ddlDepartments changes.

pseudocode...

    ' If Item exists in ddlJobs Then
    '   select item (CurrentJobID)
    ' else
    '   select index 0 and make them pick something new
    ' end if

So Close!

Updated Again

This is the code I've developed to loosely bind this. In the page_load I'm trying to pull the contents of CurrentJobID from sqlDSProfile and check to see if that value exists in ddlJobs. If it does I want to set ddlJobs.SelectedValue = to that CurrentJobID. If it doesn't I want to set the selectedindex to 0 which is a message saying "pick one" or something.

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

    If frmProfile.CurrentMode = FormViewMode.Edit Then

        ' Need to determine if the CurrentJobID returned in the select statement
        ' exists in the ddlJobs dropdownlist.  If it does, set that to the
        ' selectedvalue, if not set it to 0 so the user can select a new job.

        Dim ddlJobs As DropDownList = frmProfile.FindControl("ddlJobs")
        Dim dvProfile As DataView = sqlDSProfile.Select(DataSourceSelectArguments.Empty)
        Dim drvProfile As DataRowView = dvProfile(0)

        If ddlJobs.Items.FindByValue(drvProfile("CurrentJobID")) Is DBNull.Value Then
            ddlJobs.SelectedIndex = 0
        Else
            ddlJobs.SelectedValue = drvProfile("CurrentJobID")
        End If

    End If

End Sub

Its returning a null reference exception on the line where I'm checking for dbnull.value

Était-ce utile?

La solution 3

I have a working solution now, thanks in part to Nuux and a bunch of online research. The tip about the join statement wasn't relevant, but the tip about including "CurrentJobID" and "CurrentDeptID" in my select query was spot on.

In addition to that I had to rework the controls a little. The two cascading dropdownlists are below. The ddlJobs dropdown list behaves like a normal databound control, but it doesn't have the Bind("CurrentJobID") statement I was trying in my original post.

<asp:DropDownList ID="ddlDepartments" runat="server" Width="185px" 
    DataSourceID="sqlDSDepartments" 
    DataTextField="Department" 
    DataValueField="DeptID" 
    SelectedValue='<%# Bind("CurrentDeptID") %>' 
    AppendDataBoundItems="true" 
    AutoPostBack="True" >
        <asp:ListItem Text="--Select One--" Value="" />                                                
</asp:DropDownList>

<asp:DropDownList ID="ddlJobs" runat="server" Width="185px"
    DataSourceID="sqlDSJobs" 
    DataTextField="JobName" 
    DataValueField="JobID" 
    AppendDataBoundItems="true" 
    OnDataBinding="ddlJobs_DataBinding" />

The only thing the custom routine "ddlJobs_DataBinding" is doing is adding "--Select One--" as index 0 in the ddlJobs dropdown. I tried this in several places, like page_load, and the databound event of the formview with no success.

Protected Sub ddlJobs_DataBinding(sender As Object, e As System.EventArgs)

    Dim ddlJobs As DropDownList = frmProfile.FindControl("ddlJobs")
    Dim liSelectOne As New ListItem("--Select One--", 0)

    ddlJobs.Items.Clear()
    ddlJobs.Items.Insert(0, liSelectOne)

End Sub

The databound event of the formview frmProfile_DataBound event does do some work though. When the user clicks "edit" on the formview to enter editing mode this ensures that the dropdownlist ddlJobs has the correct job selected by default for the profile in question. If the user hasn't been assigned to a job then it defaults to selectedindex 0 which is "--Select One--" set in custom databinding event just above.

Protected Sub frmProfile_DataBound(sender As Object, e As System.EventArgs) Handles frmProfile.DataBound

    If frmProfile.CurrentMode = FormViewMode.Edit Then

        Dim ddlJobs As DropDownList = frmProfile.FindControl("ddlJobs")
        Dim dvProfile As DataView = sqlDSProfile.Select(DataSourceSelectArguments.Empty)
        Dim drProfile As DataRow = dvProfile.Table.Rows(0)

        If drProfile("CurrentJobID").ToString() = "" Then
            ddlJobs.SelectedIndex = 0
        Else
            ddlJobs.SelectedValue = drProfile("CurrentJobID").ToString()
        End If

    End If

End Sub

Finally, if the user selects a new job from ddlJobs, that value has to be fed to the database, which the ItemUpdating event of the formview handles.

Protected Sub frmProfile_ItemUpdating(sender As Object, e As System.Web.UI.WebControls.FormViewUpdateEventArgs) Handles frmProfile.ItemUpdating

    If frmProfile.CurrentMode = FormViewMode.Edit Then

        Dim ddlJobs As DropDownList = frmProfile.FindControl("ddlJobs")
        e.NewValues("CurrentJobID") = ddlJobs.SelectedValue

    End If

End Sub

Done!

Autres conseils

I had a similar issue and found a very simple resolution, (and in c#). Imagine a database with a table Questions, related to category and subcategory tables (which are also related and constrained). When trying to update existing records asp throws an error. This is the solution that I worked out thanks to the information above from Lucretius et al.

  1. Only databind the parent dropdownlist
  2. Find a way to insert the child dropdown selected value on the update event of the datasource.

As:

 protected void odseditquestion_Updating(object sender, ObjectDataSourceMethodEventArgs e)
    {
        //dynamically assign value from ddlsubcategory to odseditquestion on updating event
        //you really should not have to do this
        DropDownList ddlsubcategory = (DropDownList)fveditquestion.FindControl("ddlsubcategory");
        e.InputParameters["subcatid"] = (ddlsubcategory.SelectedValue);
    }

It works on my application. Hope it helps somebody, this one cost me half a day, such is asp!!

The problem can be if tlbEmployee columns in the SqlDSProfile in the update statement and field names used by your controls do not match. Other procedures you've followed are right.

SqlDataSource control expects field names it updates to be similar with those bound to the controls(fields) inside the DataBound control.

The Solution can be: change all the update Parameters to ControlParameters referencing the right control for each one

Update: Wait, I think the problem is your select statement of the SqlDSProfile should contain: CurrentDeptID and CurrentJobID. Try it:

<asp:SqlDataSource ID="sqlDSProfile" runat="server" 
ConnectionString="<%$ ConnectionStrings:JobsDB %>" 
SelectCommand="SELECT tblEmployee.EUID, 
            tblEmployee.DateHired, 
            tblEmployee.LastName, 
            tblEmployee.HiredLastName, 
            tblEmployee.FirstName, 
            tblEmployee.Role, 
            tblEmployee.JobGrade, 
            tblDepartments.Department, 
            tblJobs.JobName, 
            tblEmployee.CurrentShift, 
            tblEmployee.JobDate, 
            tblEmployee.IsDisplaced, 
            tblEmployee.EligibilityDate 
            tblEmployee.CurrentDeptID, 
            tblEmployee.CurrentJobID 
        FROM tblEmployee 

Advice: Test your code portion by portion.
Try the code without the dropdownlist, Test separately
Add the one drop downlist
Use select * from ... in select queries
Avoid ajax when testing
If you make it
Add portions of code portion after portion
at last use the partial updating (ajax)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top