Search code examples
c#asp.netwebformspostback

Where to set variables so that they aren't null on postback?


My webpage lets a user select one or more tools from a list of available tools (by dragging from the "available" list to the "selected" list). There is a HiddenTools hidden field that is updated every time the two lists change- the <li> in the ToolsActive list are stored as a comma separated list of ids in the HiddenTools. When the user clicks "Save", the value in the HiddenTools is stored in the database.

aspx page:

<asp:HiddenField runat="server" ID="HiddenTools"/>

/*<li> can be dragged from one list to the other. Every time the lists 
change, HiddenTools gets updated with the contents of ToolsSelected  
list, formatted as a comma separated string */

<ul id="ToolsAvailable">            
    <%foreach (KeyValuePair<int,string> tool in unusedTools){ %>
        <li id='<%= tool.Key %>'> <%= tool.Value %> </li>
    <% } %>
</ul>

<ul id="ToolsActive">
     <%foreach (KeyValuePair<int,string> aTool in selectedTools){ %>
         <li id='<%= aTool.Key %>'> <%= tool.Value %> </li>
     <% } %>
 </ul>

<asp:Button ID="btnSave" OnClick="btnSave_Click" runat="server" Text="Save"/>

code-behind:

public partial class Settings
{
    protected ToolPreferences prefs;

    protected Dictionary<int, string> tools;
    protected Dictionary<int, string> unusedTools;
    protected Dictionary<int, string> selectedTools;

    protected void Page_Load(object sender, EventArgs e)
    {
         int AccountId = getAccountId();
         if(!Page.IsPostBack){
             prefs = new ToolPreferences(AccountId);
             PopulateTools();
         }
    }

    private void PopulateTools()
    {
        tools = getPossibleTools();
        unusedTools = new Dictionary<int, string>();
        selectedTools = new Dictionary<int, string>();

        List<int> selectedList = new List<int>();
        if (!string.IsNullOrEmpty(prefs.Tools))
        {
            selectedList = prefs.Tools.Split(',').Select(int.Parse).ToList();
        }
        foreach (KeyValuePair<int, string> aTool in tools)
        {
            if (selectedList.Contains(aTool.Key))
            {
                selectedTools.Add(aTool.Key, aTool.Value);
            }
            else
            {
                unusedTools.Add(aTool.Key, aTool.Value);
            }
        }
    }

    protected void btnSavePreferences_Click(object sender, EventArgs e)
    {
        ToolPreferences tp = ToolPreferences (AccountId);
        tp.Update(HiddenTools.Value);
    }        

}

The issue is that after PostBack, the following error appears:

Object reference not set to an instance of an object.

with the following line highlighted:

<%foreach (KeyValuePair<int,string> tool in unusedTools){ %>

If I move the following two lines out of the !PageIsPostBackcheck, I don't get that error when the page reloads after postback, but I also don't see the changes the user made to the tools lists until the page is reloaded another time.

prefs = new ToolPreferences(AccountId);
PopulateTools();

Where can I set the tools variables so that the "Object reference not set" error doesn't occur?


Solution

  • Every request is handled by a fresh instance of your page-class, so all instance variables are reset (as you found out).

    Values you want to keep over requests should be stored in ViewState (to store values between postbacks in this page) or Session (to keep values between multiple pages).

    NB: do not store those values in static variables. They do keep their values between postbacks, but are also shared between all visitors.