1

我继承了一些在 webpart 控件中具有 GridView 和 DetailsView 的代码。

DetailsView 能够创建两种不同类型的对象,例如 TypeA 和 TypeB。

有一个按对象类型过滤 GridView 的下拉列表,DetailsView 有一个自动生成的插入按钮。

<asp:DetailsView ID="myDetailsView"  
    AutoGenerateInsertButton="True"
    AutoGenerateEditButton="True" 
    AutoGenerateRows="false" 
    OnItemUpdating="OnItemUpdating"
    DefaultMode="ReadOnly" 
    OnDataBound="OnDetailsViewBound"
    OnItemInserting="OnItemInserting" 
    OnModeChanging="OnDetailsViewModeChanging"        
    runat="server">

我被要求:

  1. 删除 GridView 上的过滤器;和
  2. 将新按钮/链接分成两部分,因此有一个单独的按钮用于创建每种类型的对象。

删除过滤器意味着我需要一些其他方法来跟踪我们正在创建什么样的对象。我通过将上面的内容更改为:

<asp:DetailsView ID="myDetailsView"  
    AutoGenerateInsertButton="False"
    AutoGenerateEditButton="True" 
    AutoGenerateRows="false" 
    OnItemUpdating="OnItemUpdating"
    DefaultMode="ReadOnly" 
    OnDataBound="OnDetailsViewBound"
    OnItemInserting="OnItemInserting" 
    OnModeChanging="OnDetailsViewModeChanging"        
    runat="server">

并添加

 <FooterTemplate>
        <asp:TemplateField>
            <ItemTemplate>
                <asp:LinkButton runat="server" ID="lnkCreateNewTypeA" CommandName="New" CommandArgument="TypeA" CssClass="buttonlink">New Type A</asp:LinkButton>
                <asp:LinkButton runat="server" ID="lnkCreateNewTypeB" CommandName="New" CommandArgument="TypeB" CssClass="buttonlink">New Type B</asp:LinkButton>
            </ItemTemplate>
        </asp:TemplateField>
 </FooterTemplate>

我还没有删除过滤器,因此当前更改的功能与以前相同,因为我使用的是 New 命令。我希望能够以某种方式捕获 New 事件,以便我可以将 CommandArgument 值放入隐藏字段,然后 DetailsView 将使用它来确定它正在创建的对象类型以及显示/隐藏字段。当我在代码中的所有事件处理程序中设置断点时,第一个中断的是 OnDetailsViewModeChanging,它无法访问 CommandArgument。

OnItemCommand (如果它已连接)在 DetailsView 中的任何按钮被按下时触发,并且确实让我可以访问 CommandArgument 但我不确定在此方法中究竟需要做什么来模拟当您发生时发生的事件链使用自动生成的按钮。

我是检索 CommandArgument 以在 OnItemCommand 事件处理程序中捕获它的唯一选择,还是在 New 命令上触发了其他一些事件?

谁能向我解释触发 New 命令时发生的事件顺序?

我在某处读到它将模式更改为插入,但我不知道它还能做什么。我相信在单击“插入”链接之前不会调用 OnItemInserting 方法。

任何帮助将不胜感激!


编辑:

我在 DetailsView 事件中找到了这个链接,但它没有回答我的问题。 http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.detailsview_events.aspx


编辑:

我尝试添加以下内容:

在 ascx 中:

<asp:DetailsView ID="myDetailsView"
    ...
    OnItemCommand="OnItemCommand"
    ...
    runat="server">

    ...

    <asp:TemplateField HeaderText="Object Type" HeaderStyle-CssClass="columnHeader">
        <ItemTemplate>
            <asp:HiddenField runat="server" ID="hidObjectType" Value=""/>
            <asp:Label runat="server" ID="lblObjectType"></asp:Label>
        </ItemTemplate>
    </asp:TemplateField>

在后面的代码中:

protected void OnItemCommand(object sender, DetailsViewCommandEventArgs e)
{
    if (e.CommandName.Equals("New"))
    {
        var objectType = e.CommandArgument.ToString();

        HiddenField typeHidden = this.myDetailsView.FindControl("hidObjectType") as HiddenField;
        if (typeHidden != null)
        {
            typeHidden.Value = objectType;
        }

        Label typeLabel = this.myDetailsView.FindControl("lblObjectType") as Label;
        if (typeLabel != null)
        {
            typeLabel.Text = objectType;
        }
    }
}

我发现我不需要this.myDetailsView.ChangeMode(DetailsViewMode.Insert);在这个方法中设置模式(),因为 OnDetailsViewModeChanging 事件处理程序仍然被触发。这会找到控件并正确设置它们的值。如果我再次检查 OnDetailsViewModeChanging 中的值,它们的值仍然设置,但作为此方法中逻辑的一部分,调用

this.myDetailsView.DataBind()

这会导致回发,此时,值会丢失。我尝试添加

EnableViewState="True"

但这没有任何区别。我已经查看了页面生命周期 (http://spazzarama.files.wordpress.com/2009/02/aspnet_page-control-life-cycle.pdf) 并认为这可能this.EnsureChildControls()会有所帮助,但也没有什么不同。

另一种方法是将值存储在会话中,但我宁愿不这样做。

4

1 回答 1

0

据我所知,除了OnItemCommand捕获所有命令的“新”命令之外,没有任何事件可以捕获。(注意:您需要确保CausesValidation="False"在您的 LinkBut​​ton 上进行了设置,否则代码不会进入OnItemCommand)。

单步执行代码时,发生以下情况:

  1. 按下链接按钮后,将触发 OnItemCommand。CommandName = "New" 在这里我可以检索 CommandArgument
  2. 下一个 OnModeChanging 被触发。e.NewMode = "插入"。从我看到的所有示例中,您在 DetailsView 上调用 ChangeMode,然后在其上调用 Databind()
  3. 调用 Databind() 会触发下一个 OnDataBound

我没有找到在各种事件之间保留隐藏变量值的方法,所以我最终使用了会话变量。代码如下,以防有人需要。

ASCX 中的 DetailsView 声明:

    <asp:DetailsView ID="myDetailsView"  
        AutoGenerateInsertButton="False"
        AutoGenerateEditButton="True" 
        AutoGenerateRows="false" 
        OnItemInserting="OnItemInserting" 
        OnItemUpdating="OnItemUpdating"
        OnItemCommand="OnItemCommand"
        DefaultMode="ReadOnly" 
        OnDataBound="OnDetailsViewBound"
        OnModeChanging="OnDetailsViewModeChanging"        
        runat="server">

在代码隐藏中:

不断的声明...

    private const string SESSIONKEY_MYVALUE = "MyValue";
    private const string DEFAULT_OBJECTTYPE = "TypeA";

OnItemCommand 事件处理程序...

    protected void OnItemCommand(object sender, DetailsViewCommandEventArgs e)
    {
        if (e.CommandName.Equals("New", StringComparison.InvariantCultureIgnoreCase))
        {
            var objectType = e.CommandArgument.ToString();

            HiddenField typeHidden = this.myDetailsView.FindControl("hidObjectType") as HiddenField;
            if (typeHidden != null)
            {
                typeHidden.Value = objectType;
            }

            HttpContext.Current.Session[SESSIONKEY_MYVALUE] = objectType;
        }
    }

OnModeChanging 事件处理程序....

    protected void OnDetailsViewModeChanging(Object sender, DetailsViewModeEventArgs e)
    {
        if (e.NewMode == DetailsViewMode.Insert)
        {
            this.myDetailsView.ChangeMode(DetailsViewMode.Insert);
            this.myDetailsView.DataBind();
        }
    }

OnDataBound 事件处理程序...

    protected void OnDetailsViewBound(object sender, EventArgs e)
    {
        if (this.myDetailsView.CurrentMode == DetailsViewMode.Insert)
        {
            var sessionVar = HttpContext.Current.Session[SESSIONKEY_MYVALUE];
            var objectType = sessionVar == null ? 
                DEFAULT_OBJECTTYPE : 
                sessionVar.ToString();

            var typeHidden = this.myDetailsView.FindControl("hidObjectType") as HiddenField;

            if (typeHidden != null)
            {
                typeHidden.Value = objectType;
            }
        }
    }
于 2012-12-05T05:09:30.680 回答