简体   繁体   中英

Why aren't the ASP.NET User Control properties updated within the control?

Overview

I have a ASCX user control that I am trying to use for my web application.

The control has multiple properties that need to be set in order for the control to work properly.

The control is used in a GridView. Each instance of the control needs data from the row it is on.

What I Have Tried

I have tried setting the property values using the attributes and the Eval method to assign the values. For example:

Page Code:

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

I have also tried setting the values on the RowDataBound event. For example:

Page Code:

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;
    }
}

The Problem

When I access the properties that I set using either of the methods above from the page the control is on, the values return correctly. However, if I am attempting to access the value of the property from within the codebehind of the control, it returns the default value of the property (usually NULL or string.Empty ) and not the value that was set.

For example, the FilePath property used above is declared just like any other:

UserControl Code:

/// <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;
    }
}

But when the user clicks a button on the control to perform some operation, the value of FilePath , when accessed in the UserControl's code is

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

and not the expected

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

(essentially missing the AccountYearPeriodOptionsGroupRandomTestManager.SelectedAccountValue from the string).

The odd thing is that the properties will actually perform the set operation. One of them for sure will perform the operation but then promptly loses it's value. The ModalTitle property will set the UX correctly, but accessing the value of the property afterwards fails to return what is displayed on the screen.

For example, the following set accessor will correctly set the TestManagerEditor_label values on the screen, but fails to set the value of _ModalTitle :

UserControl Code:

/// <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>";
    }
}

Does anyone know what's going on here and why my control isn't able to access or save the value of the properties that are set by its parent page?

The design of ASP.NET webforms is that the "state" or value of the controls is written to viewstate when the page is rendered. That way when you do a postback, the server code can read back what those values were and persist them between postbacks. But if you declare a string in your code, ASP.NET doesn't know that it needs to save and restore that string. So while the properties of your server controls get saved and restored, your value gets lost.

Just as ASP.NET does that for controls within a page, it also does that for server controls that are nested within your UserControl.

One real easy fix is to include a control like this as part of your UserControl:

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

Then use that to store your value instead of a string variable. Assuming that viewstate is enabled for your control, the value of that field will get written to viewstate when you do a postback. It won't get lost between postbacks.

Another thought - do you want a user to be able to see your server path (some\\path\\etc) by viewing the page source? Even in viewstate it's only encoded, not encrypted by default. It's probably better to only store in your control the part of that path that changes based on user input, not the whole path. You can retrieve the rest of the path - System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath - in your server code when you need it instead of saving it in viewstate.

If you don't want to store values in a hidden field - suppose there are multiple values or it's more complex - you can also do something like this:

You could just use a string, but I like to create a single class to store all of the state that I want to save between postbacks. That way if I need to persist another value I don't need to write the same code again to save and reload multiple values.

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

And then do this in your control:

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;
    }

Then you can read and set your values through the State property. The PreRender part saves those values into viewstate when the page is rendered. The Page_Load part reads those values back from viewstate so that they're accessible from your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM