使用ObjectDataSource摔跤-未定义其他控件和变量

本文关键字:控件 变量 其他 未定义 ObjectDataSource 摔跤 使用 | 更新日期: 2023-09-27 18:13:10

我有一个带有ObjectDataSource的Gridview,有点像这样:

<asp:GridView ID="myGridView" runat="server" AllowSorting="True" ondatabound="myGridView_DataBound" cssClass="coolTable" 
        OnRowDataBound="myGridView_RowDataBound"
         AllowPaging="True" AutoGenerateColumns="False" DataSourceID="myDataSource">
        <PagerSettings mode="NextPreviousFirstLast">
        </PagerSettings>
</asp:GridView>
<asp:ObjectDataSource ID="myDataSource" runat="server"  
         SelectMethod="GetSearchResults" EnablePaging="true"
         StartRowIndexParameterName="startIndex" 
         MaximumRowsParameterName="pageSize"
         SortParameterName="sortBy" SelectCountMethod="GetSearchCount" >   
</asp:ObjectDataSource>

Andy调用了我的函数GetSearchResults,所以这一切都很好。问题是,在GetSearchResults中,除了传递给它的变量之外,我还想使用其他变量,但当GetSearchResult运行时,它们似乎没有值。我在调试器中进行了调试,可以看到在GetSearchResults之前调用了Page_Load,但引用页面上的任何控件都会引发错误,并且属于页面的字段没有值(即使我将它们设置为Page_Load(。

我阅读了ASP.Net对象数据源-数据绑定,并浏览了链接到那里的页面生命周期概述,但仍然不明白为什么我的其他变量不可用。

但这是我真正的问题——我真的不在乎为什么它们不可用;我想知道一个好的模式,使值(在Page_Load期间设置的(可用于我的GetSearchResults函数。目前我在会议上保存东西,但这似乎有点荒谬。

[编辑以添加背景]我正在Page_Load上进行一些数据库查询,以设置一些值,这些值反过来会影响页面的布局和内容。这些值还用于修改GridView中数据的选择条件。我开始使用ObjectDataSource是因为它可以有效地分页浏览大量记录(https://msdn.microsoft.com/en-us/library/bb445504.aspx)但一开始我不知道会创建一个新的Page实例,然后调用方法——我以为它像回发一样处理。我希望避免将这些临时值保存在表单字段、会话变量等中。看起来唯一的方法可能是在正常的页面生命周期中填充Gridview,但这似乎意味着放弃Gridview的自动分页。

当您开始使用ASP.NET的DataSourceControls(ObjectDataSource、SqlDataSource、AccessDataSource等(及其对应的DataBoundControls(DropDownList、DetailsView、ListView、FormView、GridView(时,您真的想忘记ASP.NET的生命周期(并停止拖延(,如果您做得好,您甚至可以忘记代码背后的代码(aspx.cs文件(,因为现在系统可以在数据源和数据绑定控件之间实现非常自动化。

事实上,这种范式(从.NET 2.0开始才出现(确实有助于关注声明性HTML类代码。

DataSourceControl使用Parameter类型的对象集合作为其使用的方法的参数。例如,ObjectDataSource的SelectMethod使用SelectParameters属性(ParameterCollection类型(。

您可以以声明方式定义这些参数。让我们举一个例子:

<form id="form1" runat="server">
<div>
    <asp:TextBox ID="MyTextBox" Text="3" runat="server" />
    <asp:Button runat="server" Text="Run" />
    <asp:GridView ID="myGridView" runat="server" DataSourceID="myDataSource" />
    <asp:ObjectDataSource ID="myDataSource" runat="server" 
             SelectMethod="GetSearchResults"
             TypeName="WebApplication1.Code.MyModel">
        <SelectParameters>
            <asp:ControlParameter ControlID="MyTextBox" PropertyName="Text" Name="myCount" />
        </SelectParameters>
    </asp:ObjectDataSource>
</div>
</form>

在这里,myDataSource将GetSearchResults定义为某个类中MyModel类的SelectMethod(我省略了其他参数,但想法相同(方法。它还定义了一个名为myCount的参数。此参数是ControlParameter(还有其他参数(:它将连接到ASP.NET控件MyTextBox,该控件恰好被定义为TextBox控件,并将使用TextBox的Text属性作为myCount参数的值。

以下是对象模型的代码:

namespace WebApplication1.Code
{
    public class MyModel
    {
        public string Name { get; set; }
        public static IEnumerable GetSearchResults(int myCount)
        {
            for (int i = 0; i < myCount; i++)
            {
                yield return new MyModel { Name = "item " + i };
            }
        }
    }
}

正如您所看到的,该方法还定义了一个myCount参数(它区分大小写,是的,ASP.NET将自动从string转换为int,这几乎很神奇,它在后台使用TypeConverters(,因此一切都将按预期工作,没有任何代码隐藏。它是某种MV模式(M模型V视图(,由DataSourceControl/DataBoundControl进行绑定。

所以,你现在必须这样想,并使用参数。如果提供的参数列表(QueryString、Cookie、Form、Profile、Route、Session(不够,您可以提供自己的参数列表。例如,我可以定义一个特殊的参数,它将随机获得myCount(这只是一个例子:-(:

我可以这样使用它,并且我可以为这个参数定义自定义参数:

<%@ Register Namespace="WebApplication1.Code" TagPrefix="my" Assembly="WebApplication1" %>
...
<SelectParameters>
    <my:RandomParameter Name="myCount" Min="10" Max="20" />
</SelectParameters>

自定义参数类型代码:

public class RandomParameter : Parameter
{
    protected override object Evaluate(HttpContext context, Control control)
    {
        // you can get to page or environment from here with 'context' and 'control' parameters
        return new Random(Environment.TickCount).Next(Min, Max);
    }
    [DefaultValue(1)]
    public int Min
    {
        get
        {
            object o = ViewState["Min"];
            return o is int ? (int)o : 1;
        }
        set
        {
            if (Min != value)
            {
                ViewState["Min"] = value;
                OnParameterChanged();
            }
        }
    }
    [DefaultValue(10)]
    public int Max
    {
        get
        {
            object o = ViewState["Max"];
            return o is int ? (int)o : 10;
        }
        set
        {
            if (Max != value)
            {
                ViewState["Max"] = value;
                OnParameterChanged();
            }
        }
    }
}

使用ObjectDataSource摔跤-未定义其他控件和变量

在这个问题中,Andy指出了为什么页面元素在SelectMethod中不可用,下面是MSDN的解释:

如果是实例方法,则会创建业务对象并每次由SelectMethod指定的方法时销毁属性。

但是,在我的试用中,我可以通过当前上下文的Request.Forms集合访问页面变量。这有点令人困惑。但是,如果您定义了一些html表单元素,您可以在SelectMethodbyRequest.Forms集合中访问它们。您还可以访问服务器变量的值,但是,如果深入研究,您可以看到它们的名称取决于页面控制树中的层次结构。

这是我的试用版,在我的aspx文件中:

<input name="txtCriteria"></input>
<asp:Button  runat="server" ID="btnPostSearch" OnClick="btnPostSearch_Click"/>
<asp:GridView ID="myGridView" runat="server" AllowSorting="True"
     AllowPaging="True" AutoGenerateColumns="False" DataSourceID="myDataSource">
    <Columns>
        <asp:BoundField DataField="Result" />
    </Columns>
    <PagerSettings mode="NextPreviousFirstLast">
    </PagerSettings>
</asp:GridView>
<asp:ObjectDataSource ID="myDataSource" runat="server" TypeName="" 
    SelectMethod="GetSearchResults">   
</asp:ObjectDataSource>

这是文件背后的代码:

public List<SearchResult> GetSearchResults()
{
    string criteria = string.Empty;
    if (HttpContext.Current.Request["txtCriteria"] != null)
    {
        criteria = HttpContext.Current.Request["txtCriteria"];
    }
    List<SearchResult> searchResults = new List<SearchResult>();
    searchResults.Add(new SearchResult() { Result = "trial 1 " + criteria });
    searchResults.Add(new SearchResult() { Result = "trial 2 " + criteria });
    return searchResults;
}
protected void btnPostSearch_Click(object sender, EventArgs e)
{
    myGridView.DataBind();
}