【问题标题】:Why aren't the ASP.NET User Control properties updated within the control?为什么没有在控件中更新 ASP.NET 用户控件属性?
【发布时间】:2017-04-25 20:04:25
【问题描述】:

概述

我有一个 ASCX 用户控件,我正尝试将它用于我的 Web 应用程序。

控件有多个属性需要设置才能正常工作。

控件在 GridView 中使用。控件的每个实例都需要它所在行的数据。

我尝试了什么

我尝试使用属性和Eval 方法设置属性值来分配值。例如:

页面代码:

<cm:TestManagerEditor runat="server" id="TestManagerEditor" FilePath='<%# System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Some\\Path\\In\\The\\WebApp\\" + AccountYearPeriodOptionsGroupRandomTestManager.SelectedAccountValue + "\\" %>' />

我也尝试过设置RowDataBound 事件的值。例如:

页面代码:

private string PathToUserFiles = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Some\\Path\\In\\The\\WebApp\\";

protected void GridViewData_RowDataBound(object sender, GridViewRowEventArgs e)
{
    // this is the customized path to files for the selected account.
    string UserFilePath = PathToUserFiles + AccountYearPeriodOptionsGroupRandomTestManager.SelectedAccountValue + "\\";

    // set modal dialog properties and add the scripting to open those dialogs.
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        Controls_Modals_TestManagerEditor EditorModal = e.Row.FindControl("TestManagerEditor") as Controls_Modals_TestManagerEditor;

        EditorModal.FilePath = UserFilePath;
    }
}

问题

当我从控件打开的页面访问我使用上述任一方法设置的属性时,值会正确返回。但是,如果我试图从控件的代码隐藏中访问属性的值,它会返回属性的默认值(通常是 NULLstring.Empty),而不是设置的值。

例如,上面使用的FilePath 属性的声明与其他任何属性一样:

用户控制代码:

/// <summary>
/// The path to the location of the uploaded files.
/// </summary>
private string _FilePath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Some\\Path\\In\\The\\WebApp\\";

/// <summary>
/// Gets or sets the path to the location of uploaded files.
/// </summary>
public string FilePath
{
    get
    {
        return _FilePath;
    }
    set
    {
        _FilePath = value;
    }
}

但是当用户点击控件上的一个按钮进行一些操作时,FilePath的值在UserControl的代码中访问时是

System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Some\\Path\\In\\The\\WebApp\\"

不是预期的

System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath + "Some\\Path\\In\\The\\WebApp\\" + AccountYearPeriodOptionsGroupRandomTestManager.SelectedAccountValue

(基本上缺少字符串中的AccountYearPeriodOptionsGroupRandomTestManager.SelectedAccountValue)。

奇怪的是,这些属性实际上会执行set 操作。其中一个肯定会执行该操作,但随后会立即失去其价值。 ModalTitle 属性将正确设置 UX,但之后访问该属性的值无法返回屏幕上显示的内容。

例如,以下设置访问器将正确设置屏幕上的TestManagerEditor_label 值,但无法设置_ModalTitle 的值:

用户控制代码:

/// <summary>
/// The text to display in the title of the Modal Dialog Box.
/// </summary>
private string _ModalTitle = "Test Manager";

/// <summary>
/// Gets or sets the text to display in the title of the Modal Dialog Box.
/// </summary>
public string ModalTitle
{
    get
    {
        return _ModalTitle;
    }
    set
    {
        _ModalTitle = value;
        TestManagerEditor_label.InnerText = value + " ";
        TestManagerEditor_label.InnerHtml = TestManagerEditor_label.InnerHtml + "<span class=\"fa fa-pencil\"></span>";
    }
}

有谁知道这里发生了什么以及为什么我的控件无法访问或保存其父页面设置的属性值?

【问题讨论】:

  • 用户控件有自己的生命周期。尝试在渲染事件或数据绑定后读取/写入您的属性——您可能会看到不同的结果。 msdn.microsoft.com/en-us/library/ms178472.aspx
  • 我会试试的,但我仍然很困惑为什么这些属性对页面“可见”而不是控件本身。
  • 我想是因为那个时候,Eval 还没有运行。它可能在 Init() msdn.microsoft.com/en-us/library/… 之前运行
  • @KevinRaffay,我尝试遍历控件的 PreRender 事件和 Render 事件的 GridView 行,但没有成功。但是,在控件的 Load 事件上设置属性时,我是成功的。不知道为什么会这样,但是通过控件的属性设置属性值不起作用。奇怪的。谢谢您的帮助!它现在似乎可以工作了!

标签: c# asp.net properties user-controls asp-usercontrols


【解决方案1】:

ASP.NET webforms 的设计是在页面被渲染时将控件的“状态”或值写入视图状态。这样,当您进行回发时,服务器代码可以读回这些值是什么,并在回发之间保留它们。但是如果您在代码中声明一个字符串,ASP.NET 不知道它需要保存和恢复该字符串。因此,当您的服务器控件的属性得到保存和恢复时,您的价值就会丢失。

正如 ASP.NET 对页面中的控件执行此操作一样,它也对嵌套在 UserControl 中的服务器控件执行此操作。

一个真正简单的解决方法是在您的 UserControl 中包含这样的控件:

<asp:hiddenfield id="filepath" runat="server">

然后使用它来存储您的值而不是字符串变量。假设为您的控件启用了视图状态,当您执行回发时,该字段的值将被写入视图状态。它不会在回发之间丢失。

另一个想法 - 您是否希望用户能够通过查看页面源来查看您的服务器路径(some\path\etc)?即使在视图状态中,它也只是编码,默认情况下不加密。 将根据用户输入更改的路径部分而不是整个路径存储在您的控件中可能会更好。您可以在需要时在服务器代码中检索路径的其余部分 - System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath,而不是将其保存在视图状态中。

如果您不想将值存储在隐藏字段中 - 假设有多个值或者它更复杂 - 您也可以执行以下操作:

您可以只使用一个字符串,但我喜欢创建一个类来存储我想要在回发之间保存的所有状态。这样,如果我需要保留另一个值,我不需要再次编写相同的代码来保存和重新加载多个值。

[Serializable]
public class ControlState
{
    public string FilePath{get;set;}
}

然后在您的控制中执行此操作:

public partial class YourControl : System.Web.UI.UserControl
{
    private ControlState _controlState;

    public ControlState State { get { return _controlState; } }

    protected void Page_Load(object source, EventArgs e)
    {
        _controlState= ViewState["controlState"] as ControlState ?? new ControlState();
    }

    protected void Page_PreRender(object sender, EventArgs e)
    {
        ViewState["controlState"] = _controlState;
    }

然后您可以通过State 属性读取和设置您的值。 PreRender 部分在呈现页面时将这些值保存到视图状态中。 Page_Load 部分从视图状态中读回这些值,以便您的代码可以访问它们。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-17
    • 1970-01-01
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 2015-08-25
    • 2019-04-04
    相关资源
    最近更新 更多