【问题标题】:ASP.NET Modifying Control Tree DynamicallyASP.NET 动态修改控制树
【发布时间】:2011-07-21 17:04:05
【问题描述】:

我正在尝试将控件动态地拖放到我的控件树中。例如:

在特定条件下,我调用:

    private void resetPanel()
    {
        Panel.Controls.Clear();
        Panel.Controls.Add(Image);
        Panel.Controls.Add(HiddenField);
    }

我的主要目标是如何让添加的控件在回发中持续存在?

当我使用文本框和标题调用另一个类似的函数时,它会完美地保留下来。但是,图像会丢失其 URL 和属性。

我知道要使动态控件持久存在,您必须将其添加到 Init 中,并且您必须对控件树负责,因此需要在每次回发时将动态控件添加到树中。

那么为什么它适用于跨回传的文本框和标签,但您不能为图像和隐藏字段添加控件?

谢谢, 布赖恩

--更新和解决方案--

我在我的代码中发现了一个错误,并且 HiddenField 值在回发中确实存在。我选择的解决方案是使用 ViewState 来保存值,然后在每次回帖时恢复我的动态控件。

--编辑--

感谢您的回复,由于我的问题可能有更好的解决方案,这里有一些代码有望显示我如何调用该方法以及为什么需要这样做。

    public void resetTitlePanel()
    {
        // Restylize the panel to initial state
        TitlePanel.Controls.Clear();
        TitlePanel.BorderColor = System.Drawing.Color.Maroon;
        TitlePanel.BorderStyle = BorderStyle.Dashed;
        TitlePanel.Enabled = true;

        // Set the new control properties to initial state
        Label TitleLabel = new Label();
        TitleLabel.ID = "TitleLabel";

        TextBox TitleTxtBox = new TextBox();
        TitleTxtBox.ID = "TitleTxtBox";

        // Add the new controls to the container
        TitlePanel.Controls.Add(TitleLabel);
        TitlePanel.Controls.Add(TitleTxtBox);

        // Set the reference of this to the new dynamic control
        this.TitleLabel = TitleLabel;
        this.TitleTxtBox = TitleTxtBox;
    }

    public void resetImagePanel()
    {
        // Restylize the panel to initial state
        ImagePanel.Controls.Clear();
        ImagePanel.BorderColor = System.Drawing.Color.Blue;
        ImagePanel.BorderStyle = BorderStyle.Dashed;
        ImagePanel.HorizontalAlign = HorizontalAlign.NotSet;

        // Set the new control properties to initial state
        Image AddImage = new Image();
        AddImage.ImageUrl = "~/Resources/Icons/picture_add.png";
        AddImage.ID = "AddImage";

        HiddenField HiddenImage = new HiddenField();
        HiddenImage.ID = "HiddenImage";

        // Add the new controls to the container
        ImagePanel.Controls.Add(AddImage);
        ImagePanel.Controls.Add(HiddenImage);

        // Set the reference of this to the new dynamic control
        this.AddImage = AddImage;
        this.HiddenImage = HiddenImage;
    }

调用方法:

private void copyFromSlide(TemplateControl destination, Template source)
    {
        // Reset the template
        destination.resetTitlePanel();
        destination.resetImagePanel();

        destination.Title = source.Title;
        // Find the path from the database and assign it to the control
        destination.ImagePath = modData.getImagePath((int)source.ImageID);
    }

所以...我知道代码很复杂,也许比它应该的复杂。此外,我只是一个初学者,所以它可能质量较差,对此我深表歉意。

主要注意事项是:

  • 有 2 个用户控件相互交互。
  • 这完全适用于 !IsPostback。
  • ViewStateEnable 默认为 true,即使我明确指定它为 true,我也会得到相同的结果。
  • 这完全适用于由标签和文本框组成的标题面板,两者都保留其值。
  • 我知道我将静态和动态控件混合在一起。我习惯了 C,所以我不确定是否可以将对象指针移动到新的动态对象。

问题是,在分配图像路径时,该值不会在回发时保留。

我需要删除并重新添加控件,因为在特定条件下我将删除控件并添加标签,如上所述,这没有问题。我认为我不需要再次初始化控件的原因是因为我正在添加一个有根面板,如下所示:

http://weblogs.asp.net/infinitiesloop/archive/2006/08/30/TRULY-Understanding-Dynamic-Controls-_2800_Part-3_2900_.aspx

我希望这会增加一些清晰度。

再次感谢,

-布赖恩

【问题讨论】:

  • 您是说您还添加了动态文本框和标签以及动态图像和隐藏字段?您是说添加动态文本框和标签并且它们会持续存在,而图像和隐藏字段则不会?
  • 嗨 Gangelo,这或多或少就是我要说的。但是,除了图像和隐藏字段之外,文本框和标签是在一个函数中添加的。

标签: c# .net asp.net


【解决方案1】:

在 InitComplete 事件触发之前,ViewState 不会跟踪更改。如果您在此之前进行更改并将它们存储在 ViewState 中(例如在 Init 中),这些更改将不会生成新的 viewstate 键。 Init 应该用于从视图状态重建您的控件。 Init 事件之后的事件是您应该在视图状态中为这些控件设置新值的地方,以便它们将被持久化。

回答您的第二个问题:Image 和 HiddenField 控件不响应任何事件(例如单击事件),因此不需要重建。这就是为什么您会看到 TextBox 和 Label 控件与 Image 和 HiddenField 控件之间的不同行为。

在页面视图状态下存储确定何时添加和删除这些控件的数据可能更容易,并且只需在每次页面加载时重新创建控件。

【讨论】:

  • 您好查尔斯,感谢您的回复。我一直在进一步研究这一点。我不知道标签控件会响应任何事件。此外,即使我使用静态控件,当我更改图像 URL 时,回发后它也不会粘住。虽然,我在 preRender 之前但在加载之后从另一个用户控件的页面加载更改了 imageURL。哈哈,也许复杂性阻止了它按预期运行。谢谢。 -布赖恩
  • 我更新了我的答案。每次从确定树中应该包含什么的数据中创建树时,您可能会有更好的运气。您可以将该数据存储在页面视图状态中。
  • 嗨,查尔斯,我完全同意你的回答。感谢您花时间回答我的问题。
  • 嗨,查尔斯,只是为了让你知道我尝试了你的答案,而且效果很好!再次感谢!
【解决方案2】:

您是否在这些控件上启用了 ViewState?

本文档的备注部分有一些内容您可能想查看here

【讨论】:

  • 嗨 Gangelo,我已经在这些控件上启用了 ViewState,但 imageURL 仍然没有保留。谢谢。
  • 这些控件的视图状态默认是启用的。
  • @Brian - 当您查看呈现的页面源时,您确定控件实际上正在呈现吗?您是说您在 !Page.IsPostBack 上看到图像并且图像仍然在 Page.IsPostBack 上呈现,但 ImageUrl 属性被清除了吗?
  • @Charles - 他可能会偶然禁用它。
  • @gangelo - 我同意,它只是与您的答案相关的有用信息。
【解决方案3】:

您需要做的是始终在 OnLoad() 发生之前(通常在 OnInit() 上)将所有控件添加到页面(或用户控件)。

这是因为 ASP.NET 在 OnLoad() 上从 ViewState 或 Request.Form 加载控件值。

事实上,在回发之间,没有任何“控件”被持久化,它只是在 ViewState 或 Request.Form 中的回发之间保留的控制值。 (不管是在标记中添加还是动态添加)正如我上面所说的,唯一重要的是控件在 OnLoad() 之前添加到页面中。

即使您在 OnLoad 之后添加元素,我也应该添加,您仍然可以像这样读取控件的值(在回发中):

Request.Form[txtName.UniqueID]

有关 ASP.NET 中控件生命周期的更多信息,请参见此处;

http://msdn.microsoft.com/en-us/library/ms178472.aspx

【讨论】:

  • 您好 Valipour,感谢您的回复。这对于 Image.imageURL 等属性是否适用?谢谢。
  • 为什么需要从Request中加载ImageUrl? ImageUrl 不是表单的一部分,所以它总是在初始化,不是吗?
  • 嗨 Valipour,你是对的。 ImageUrl 不是表单的一部分。我遇到问题的控件是动态加载的图像,不会在回发中持续存在。既然您说的是元素的值如何在回发而不是控件本身中持续存在,即使在 onload 之后也是如此。我想知道如何访问图像的 url 值。否则,在回发时图像会中断。
  • 我在回答中提到的重点是:您需要在“OnInit”中动态添加图像。 ImageUrl 不是从表单中读取的,因此您必须分配它,但 OnInit() 总是发生(在其他任何事情之前),因此您的图像之后会有 ImageUrl。如果您在调用该函数时向我们展示这将有很大帮助。
  • 您好 Valipour,谢谢。我添加了代码来向您展示调用函数。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-30
  • 1970-01-01
相关资源
最近更新 更多