1

我有一个用于查看、编辑和将项目插入 MSSQL 数据库的 FormView。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 的 - 文本框工作正常)?过滤工作完美(即,FormView 仅显示用户输入的基于记录的参数);如果您想知道WhereLike扩展方法的作用,可以查看此问题的答案。

4

2 回答 2

0

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

解决方案:调整绑定

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

}

为了持久化您的数据,请使用 ViewState

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

于 2012-08-30T16:31:45.077 回答
0

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

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

我的意思的代码片段更新:

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

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

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

于 2012-08-31T21:40:36.100 回答