5

I am dynamically adding items to a CheckBoxList that configures some settings in my web part. When I set the properties and click "OK" everything on my page works as expected and displays that data it should for the check boxes selected.

My problem is that if I leave the page and come back, it no longer has the values selected and my web part displays as if no check boxes are selected.

Below is the code I am using to create the custom web part property and save the values:

[ToolboxItemAttribute(false)]
public class MultiPart : WebPart
{
    // Visual Studio might automatically update this path when you change the Visual Web Part project item.
    private const string _ascxPath = @"~/_CONTROLTEMPLATES/MultiPart/MultiPart/MultiPartUserControl.ascx";
    public List<ListItem> SelectedTabs { get; set; }


    protected override void CreateChildControls()
    {
        MultiPartUserControl control = Page.LoadControl(_ascxPath) as MultiPartUserControl;
        if (control != null)
            control.myWebPart = this;
        Controls.Add(control);
    }

    public override EditorPartCollection CreateEditorParts()
    {
        ArrayList editorArray = new ArrayList();
        MyEditorPart edPart = new MyEditorPart();
        edPart.ID = this.ID + "_editorPart1";
        editorArray.Add(edPart);
        EditorPartCollection editorParts = new EditorPartCollection(editorArray);
        return editorParts;
    }

}

public class MyEditorPart : EditorPart
{
    private Label lbl_Options;
    private CheckBoxList cbl_WebParts;

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        cbl_WebParts = new CheckBoxList();
        lbl_Options = new Label();
        lbl_Options.Text = "<strong>Select which web parts to include:</strong><br />";

        string _ascxPath = @"~/_CONTROLTEMPLATES/MultiPart/MultiPart/MultiPartUserControl.ascx";
        Control ascxControl = Page.LoadControl(_ascxPath);

        foreach (Control c in ascxControl.FindControl("tabs").Controls)
        {
            if(c.GetType().Equals(typeof(HtmlGenericControl)) && ((HtmlGenericControl)c).TagName.ToLower() == "div")
            {
                cbl_WebParts.Items.Add(new ListItem(((HtmlGenericControl)c).Attributes["title"], c.ID));
            }
        }

        Controls.Add(lbl_Options);
        Controls.Add(cbl_WebParts);
    }

    public override bool ApplyChanges()
    {
        EnsureChildControls();
        MultiPart webPart = WebPartToEdit as MultiPart;
        if (webPart != null)
        {
            if (webPart.SelectedTabs == null)
            {
                webPart.SelectedTabs = new List<ListItem>();
            }

            foreach (ListItem li in cbl_WebParts.Items)
            {
                if (li.Selected)
                {
                    webPart.SelectedTabs.Add(li);
                }
            }
        }
        return true;
    }

    public override void SyncChanges()
    {
        EnsureChildControls();
        MultiPart webPart = WebPartToEdit as MultiPart;

        if (webPart != null && webPart.SelectedTabs != null)
        {
            foreach (ListItem li in webPart.SelectedTabs)
            {
                cbl_WebParts.Items.FindByValue(li.Value).Selected = true;
            }
        }
    }

Is there anything else I should be doing to get these values to persist across visits?

1 Answer 1

9

Your SelectedTabs property should be persisted. Try use this code:

[Personalizable(PersonalizationScope.Shared),
 WebBrowsable(false)]
public List<ListItem> SelectedTabs { get; set; }

Update:

Also, you should not store ListItem's. I changed List<ListItem> to List<string> and fixed some code, and it is working on my machine now. Here is the resulting code:

[ToolboxItemAttribute(false)]
public class VisualWebPart1 : WebPart
{
    // Visual Studio might automatically update this path when you change the Visual Web Part project item.
    private const string _ascxPath = @"~/_CONTROLTEMPLATES/MultiPart/MultiPart/MultiPartUserControl.ascx";

    [Personalizable(PersonalizationScope.Shared),
    WebBrowsable(false)]
    public List<string> SelectedTabs { get; set; }


    protected override void CreateChildControls()
    {
        Control control = Page.LoadControl(_ascxPath);
        Controls.Add(control);
    }

    public override EditorPartCollection CreateEditorParts()
    {
        ArrayList editorArray = new ArrayList();
        MyEditorPart edPart = new MyEditorPart();
        edPart.ID = this.ID + "_editorPart1";
        editorArray.Add(edPart);
        EditorPartCollection editorParts = new EditorPartCollection(editorArray);
        return editorParts;
    }

}

public class MyEditorPart : EditorPart
{

    private Label lbl_Options;
    private CheckBoxList cbl_WebParts;

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        cbl_WebParts = new CheckBoxList();
        lbl_Options = new Label();
        lbl_Options.Text = "<strong>Select which web parts to include:</strong><br />";

        string _ascxPath = @"~/_CONTROLTEMPLATES/MultiPart/MultiPart/MultiPartUserControl.ascx";
        Control ascxControl = Page.LoadControl(_ascxPath);

        foreach (Control c in ascxControl.FindControl("tabs").Controls)
        {
            if(c.GetType().Equals(typeof(HtmlGenericControl)) && ((HtmlGenericControl)c).TagName.ToLower() == "div")
            {
                cbl_WebParts.Items.Add(new ListItem(((HtmlGenericControl)c).Attributes["title"], c.ID));
            }
        }

        Controls.Add(lbl_Options);
        Controls.Add(cbl_WebParts);
    }

    public override bool ApplyChanges()
    {
        EnsureChildControls();
        VisualWebPart1 webPart = WebPartToEdit as VisualWebPart1;
        if (webPart != null)
        {
            if (webPart.SelectedTabs == null)
            {
                webPart.SelectedTabs = new List<string>();
            }

            foreach (ListItem li in cbl_WebParts.Items)
            {
                if (li.Selected)
                {
                    webPart.SelectedTabs.Add(li.Value);
                }
            }
        }
        return true;
    }

    public override void SyncChanges()
    {
        EnsureChildControls();
        VisualWebPart1 webPart = WebPartToEdit as VisualWebPart1;

        if (webPart != null && webPart.SelectedTabs != null)
        {
            foreach (string value in webPart.SelectedTabs)
            {
                cbl_WebParts.Items.FindByValue(value).Selected = true;
            }
        }
    }
}
10
  • When I add that I get the following error at the top of the Edit pane: Cannot save all of the property settings for this Web Part. An error has occurred. May 3, 2011 at 17:35
  • That's much better :) Now you can observe your ULS logs and grab the exception message from there. May 3, 2011 at 17:39
  • When I monitor the ULS logs all I see is Leaving Monitored Scope (PostResolveRequestCacheHandler). Execution Time=60.653588654424 when I click OK or Apply. No errors are being thrown in the log. May 3, 2011 at 17:49
  • 2
    I'm not Jon Skeet, so I can't explain accurately. But it is always a bad idea for me - to store somewhere in db webcontrols instances and their helper classes instances. These are very complex classes with much logic and bindings inside, so better to deal with more lightweight classes instead. For example, if you want to store Text+Value, you can use Dictionary<string,string>. May 3, 2011 at 18:50
  • 3
    @omlin thats exactly right. ListItem isnt serializable so it cannot be used msdn.microsoft.com/en-us/library/…. ArrayList is, btw.msdn.microsoft.com/en-us/library/… May 3, 2011 at 22:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.