保存FormView的筛选结果时,DropDownList值为空

时间:2012-08-28 15:57:19

标签: c# linq linq-to-sql formview linqdatasource

我有一个FormView,用于查看,编辑和插入MSSQL数据库中的项目。 FormView连接到LinqDataSource,我使用它的Selecting事件根据查询字符串中传递的参数(列)过滤FormView中显示的数据。

在FormView中,我有一个显示相关表中值的DropDownList。一切都按原样运行,除非我尝试编辑 - 由于某种原因,当我尝试保存编辑时,DropDownList的选定值总是为空(即使我选择了一个值)。插件可以正常工作。

我已将问题追溯到我进行过滤的Selecting事件。如果我注释掉进行过滤的方法,它会成功更新项目 - 但我无法弄清楚过滤为什么会破坏更新。

这是我的(缩短的)FormView:

<asp:FormView ID="fvData" runat="server" AllowPaging="True" 
    DataKeyNames="ID" DataSourceID="ldsData" 
    ondatabound="fvData_DataBound">
    <EditItemTemplate>
        <table class="pad5">
            <tr>
                <td class="field-name">AREA:</td>
                <td><asp:DropDownList ID="cboAREA" runat="server" DataTextField="AREA_NAME" DataValueField="AREA1" SelectedValue='<%# Bind("AREA") %>' DataSourceID="ldsAreas" /></td>
            </tr>
            <tr>
                <td class="field-name">LOOP:</td>
                <td><asp:TextBox ID="txtLOOP" runat="server" Text='<%# Bind("LOOP") %>' /></td>
            </tr>
            <tr>
                <td class="field-name">LOOP DESCRIPTION:</td>
                <td><asp:TextBox ID="txtLOOP_DESCRIPTION" runat="server" 
            Text='<%# Bind("LOOP_DESCRIPTION") %>' style="width: 600px" /></td>
            </tr>
        </table>

        <asp:Button ID="btnUpdate" runat="server" Text="Update" CommandName="Update" CausesValidation="True" />
        <asp:Button ID="btnCancel" runat="server" Text="Cancel" CommandName="Cancel" CausesValidation="False" />
    </EditItemTemplate>
    <InsertItemTemplate>
        <table class="pad5">
            <tr>
                <td class="field-name">AREA:</td>
                <td>
                    <asp:DropDownList ID="cboAREA" runat="server" DataTextField="AREA_NAME" 
                        DataValueField="AREA1" SelectedValue='<%# Bind("AREA") %>' AppendDataBoundItems="true" DataSourceID="ldsAreas">
                            <asp:ListItem Text="" Value="" />
                        </asp:DropDownList>
                </td>
            </tr>
            <tr>
                <td class="field-name">LOOP:</td>
                <td><asp:TextBox ID="txtLOOP" runat="server" Text='<%# Bind("LOOP") %>' /></td>
            </tr>
            <tr>
                <td class="field-name">LOOP DESCRIPTION:</td>
                <td><asp:TextBox ID="txtLOOP_DESCRIPTION" runat="server" 
            Text='<%# Bind("LOOP_DESCRIPTION") %>' style="width: 600px" /></td>
            </tr>
        </table>

        <asp:Button ID="btnInsert" runat="server" Text="Insert" CommandName="Insert" CausesValidation="True" />
        <asp:Button ID="btnCancel" runat="server" Text="Cancel" CommandName="Cancel" CausesValidation="False" />
    </InsertItemTemplate>
</asp:FormView>

LinqDataSource:

<asp:LinqDataSource ID="ldsData" runat="server" 
    ContextTypeName="E_and_I.EAndIDataDataContext" EnableDelete="True" 
    EnableInsert="True" EnableUpdate="True" EntityTypeName="" 
    TableName="INSTRUMENT_LOOP_DESCRIPTIONs" onselecting="ldsData_Selecting" OrderBy="ID ASC" >
</asp:LinqDataSource>

我的ldsData_Selecting方法:

protected void ldsData_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
    EI.FilterData<INSTRUMENT_LOOP_DESCRIPTION>(ref e, db.INSTRUMENT_LOOP_DESCRIPTIONs, this.db);
}

最后EI.FilterData

public static void FilterData<T>(ref LinqDataSourceSelectEventArgs e, IEnumerable<T> source, EAndIDataDataContext db)
{
    if (HttpContext.Current.Request.QueryString.Keys.Count > 0)
    {
        var result = source.AsQueryable();
        bool filtered = false;

        // get column names
        var columnNames = db.Mapping.MappingSource.GetModel(typeof(EAndIDataDataContext)).GetMetaType(typeof(T)).DataMembers;

        foreach (string key in HttpContext.Current.Request.QueryString.Keys)
        {
            string val = HttpContext.Current.Request.QueryString[key];

            // check the query string key exists as a column in the table, etc
            if (columnNames.SingleOrDefault(c => c.Name == key) != null && val.Trim() != "" && val != "*")
            {
                result = result.WhereLike(key, val.Replace("?", "_").Replace("*", "%"));
                filtered = true;
            }
        }

        if (filtered)
            e.Result = result;
    }
}

有什么理由过滤结果会破坏更新(只有DropDownList&#39; s - 文本框工作正常)?过滤效果很好(也就是说,FormView只显示用户输入的基于记录的参数);如果您想知道WhereLike扩展方法的作用,可以查看this question's个答案。

2 个答案:

答案 0 :(得分:0)

因为当您通过编辑发布数据时,您会重新绑定数据,因此您将删除所选的值。

解决方案:调整你的绑定

If( !  IsPostBack)
{
  //Here realize your bind of data

}

要保留数据,请使用ViewState

使用此解决方案发布时不要重新绑定数据,因此ViewState包含您选择的值

答案 1 :(得分:0)

你的两个案例的下拉列表有所不同,我认为这可能是导致这种情况的原因。对于Insert,您有AppendDataBoundItems =“true”,而对于它上面的Update表单,此标志未设置(并且默认为false)。在提交表单方面,这意味着,对于“插入”表单,当它重新绑定时,它会将项目附加到当前列表而不是清除它们;但是对于Update表单,因为它没有设置为append,它会清除项目然后绑定它们 - 所以Binding在两种情况下都会发生,但是在Update表单的情况下,它会在发生这种情况时清除项目,给你空白数据。

而不是仅仅拒绝Postback上的过滤,这会导致您的表单最终失败,而是根据CAUSED回发的控件进行过滤。在函数的顶部,您可以捕获导致回发的控件ID,然后只有当它不是来自触发数据存储步骤的按钮的回发时才可以进行过滤。如果这已经到位,我相信你应该能够完全取消AppendDataBoundItems标志。

我的意思的代码段更新:

string initControl = Request.Form["__EVENTTARGET"];
if (!IsPostBack || (initControl != "btnInsert" && initControl != "btnUpdate") {
    // code here
}

这样做是为了扩展对PostBack的检查,以便条件允许,如果不是回发(你之前测试过),但是关键的是,如果表单被回发,它也会允许列表更新,只要控件回发不是触发依赖于这些绑定元素的内容的事件的回发。这应该意味着你避免了它只适用于第一页加载的问题。

此外,如果您需要控件进行绑定,则可以向脚本添加全局布尔变量;默认情况下将其设置为False,如果不满足上述条件,则将其设置为True(即,如果您阻止绑定)。然后你可以检查Page_PreRender函数中的布尔值,如果它设置为true,你可以在该步骤执行控件的后期绑定(只有在插入/更新事件已经处理后才会触发,所以任何绑定都在该点将不再影响表单处理的结果。)