views:

109

answers:

1

This is a classic sort of question, I suppose, but it seems that most people are interested in having the textbox cause a postback. I'm not. I just want the event to fire when a postback occurs.

I have created a webpart with a custom editorpart. The editorpart renders with a textbox and a button. Clicking the button causes a dialog to open. When the dialog is closed, it sets the value of the textbox via javascript and then does __doPostBack using the ClientID of the editorpart.

The postback happens, but the TextChanged event never fires, and I'm not sure if it's a problem with the way __doPostBack is invoked, or if it's because of the way I'm setting up the event handler, or something else. Here's what I think is the relevant portion of the code from the editorpart:

protected override void CreateChildControls()
{
    _txtListUrl = new TextBox();            

    _txtListUrl.ID = "targetSPList";
    _txtListUrl.Style.Add(HtmlTextWriterStyle.Width, "60%");
    _txtListUrl.ToolTip = "Select List";
    _txtListUrl.CssClass = "ms-input";
    _txtListUrl.Attributes.Add("readOnly", "true");
    _txtListUrl.Attributes.Add("onChange", "__doPostBack('" + this.ClientID + "', '');");
    _txtListUrl.Text = this.ListString;                                  

    _btnListPicker = new HtmlInputButton();
    _btnListPicker.Style.Add(HtmlTextWriterStyle.Width, "60%");
    _btnListPicker.Attributes.Add("Title", "Select List");
    _btnListPicker.ID = "browseListsSmtButton";
    _btnListPicker.Attributes.Add("onClick", "mso_launchListSmtPicker()");
    _btnListPicker.Value = "Select List";

    this.AddConfigurationOption("News List", "Choose the list that serves as the data source.",
        new Control[] { _txtListUrl, _btnListPicker });

    if (this.ShowViewSelection)
    {
        _txtListUrl.TextChanged += new EventHandler(_txtListUrl_TextChanged);
        _ddlViews = new DropDownList();
        _ddlViews.ID = "_ddlViews";
        this.AddConfigurationOption("View", _ddlViews);
    }
}

protected override void OnPreRender(EventArgs e)
{   
    ScriptLink.Register(this.Page, "PickerTreeDialog.js", true);

    string lastSelectedListId = string.Empty;
    if (!this.WebId.Equals(Guid.Empty) && !this.ListId.Equals(Guid.Empty))
    {
        lastSelectedListId = SPHttpUtility.EcmaScriptStringLiteralEncode(
            string.Format("SPList:{0}?SPWeb:{1}:", this.ListId.ToString(), this.WebId.ToString()));
    }

    string script = "\r\n                var lastSelectedListSmtPickerId = '" + lastSelectedListId  + "';" 
                  + "\r\n                function mso_launchListSmtPicker(){"
                  + "\r\n                    if (!document.getElementById) return;"
                  + "\r\n" 
                  + "\r\n                    var listTextBox = document.getElementById('" + SPHttpUtility.EcmaScriptStringLiteralEncode(_txtListUrl.ClientID) + "');" 
                  + "\r\n                    if (listTextBox == null) return;"
                  + "\r\n"
                  + "\r\n                    var serverUrl = '" + SPHttpUtility.EcmaScriptStringLiteralEncode(SPContext.Current.Web.ServerRelativeUrl) + "';"
                  + "\r\n"
                  + "\r\n                    var callback = function(results) {"
                  + "\r\n                        if (results == null || results[1] == null || results[2] == null) return;"
                  + "\r\n"
                  + "\r\n                        lastSelectedListSmtPickerId = results[0];"
                  + "\r\n                        var listUrl = '';"
                  + "\r\n                        if (listUrl.substring(listUrl.length-1) != '/') listUrl = listUrl + '/';"
                  + "\r\n                        if (results[1].charAt(0) == '/') results[1] = results[1].substring(1);"
                  + "\r\n                        listUrl = listUrl + results[1];"
                  + "\r\n                        if (listUrl.substring(listUrl.length-1) != '/') listUrl = listUrl + '/';"
                  + "\r\n                        if (results[2].charAt(0) == '/') results[2] = results[2].substring(1);"
                  + "\r\n                        listUrl = listUrl + results[2];"
                  + "\r\n                        listTextBox.value = listUrl;"
                  + "\r\n                        __doPostBack('" + this.ClientID + "','');"
                  + "\r\n                    }"
                  + "\r\n                    LaunchPickerTreeDialog('CbqPickerSelectListTitle','CbqPickerSelectListText','websLists','', serverUrl, lastSelectedListSmtPickerId,'','','/_layouts/images/smt_icon.gif','', callback);"
                  + "\r\n                }";

    this.Page.ClientScript.RegisterClientScriptBlock(typeof(ListPickerEditorPart), "mso_launchListSmtPicker", script, true);

    if ((!string.IsNullOrEmpty(_txtListUrl.Text) && _ddlViews.Items.Count == 0) || _listSelectionChanged)
    {
        _ddlViews.Items.Clear();
        if (!string.IsNullOrEmpty(_txtListUrl.Text))
        {
            using (SPWeb web = SPContext.Current.Site.OpenWeb(this.WebId))
            {
                foreach (SPView view in web.Lists[this.ListId].Views)
                {
                    _ddlViews.Items.Add(new ListItem(view.Title, view.ID.ToString()));
                }
            }
            _ddlViews.Enabled = _ddlViews.Items.Count > 0;
        }
        else
        {
            _ddlViews.Enabled = false;
        }
    }

    base.OnPreRender(e);
}

void _txtListUrl_TextChanged(object sender, EventArgs e)
{
    this.SetPropertiesFromChosenListString(_txtListUrl.Text);
    _listSelectionChanged = true;
}

Any ideas?

Update: I forgot to mention these methods, which are called above:

protected virtual void AddConfigurationOption(string title, Control inputControl)
{
    this.AddConfigurationOption(title, null, inputControl);
}

protected virtual void AddConfigurationOption(string title, string description, Control inputControl)
{
    this.AddConfigurationOption(title, description, new List<Control>(new Control[] { inputControl }));
}

protected virtual void AddConfigurationOption(string title, string description, IEnumerable<Control> inputControls)
{
    HtmlGenericControl divSectionHead = new HtmlGenericControl("div");
    divSectionHead.Attributes.Add("class", "UserSectionHead");
    this.Controls.Add(divSectionHead);

    HtmlGenericControl labTitle = new HtmlGenericControl("label");
    labTitle.InnerHtml = HttpUtility.HtmlEncode(title);
    divSectionHead.Controls.Add(labTitle);

    HtmlGenericControl divUserSectionBody = new HtmlGenericControl("div");
    divUserSectionBody.Attributes.Add("class", "UserSectionBody");
    this.Controls.Add(divUserSectionBody);

    HtmlGenericControl divUserControlGroup = new HtmlGenericControl("div");
    divUserControlGroup.Attributes.Add("class", "UserControlGroup");
    divUserSectionBody.Controls.Add(divUserControlGroup);

    if (!string.IsNullOrEmpty(description))
    {
        HtmlGenericControl spnDescription = new HtmlGenericControl("div");
        spnDescription.InnerHtml = HttpUtility.HtmlEncode(description);
        divUserControlGroup.Controls.Add(spnDescription);
    }

    foreach (Control inputControl in inputControls)
    {
        divUserControlGroup.Controls.Add(inputControl);
    }
    this.Controls.Add(divUserControlGroup);

    HtmlGenericControl divUserDottedLine = new HtmlGenericControl("div");
    divUserDottedLine.Attributes.Add("class", "UserDottedLine");
    divUserDottedLine.Style.Add(HtmlTextWriterStyle.Width, "100%");
    this.Controls.Add(divUserDottedLine);
}
+1  A: 

Hi

It can help, if the class declaring the event handler (in your case the editorpart, I guess) implements System.Web.UI.INamingContainer. And do you add _txtListUrl to the Controls collection?

EDIT:

  • Make sure that the AutoPostBack property of _txtListUrl is set to true (_txtListUrl.AutoPostBack = true).

  • _txtListUrl.Attributes.Add("onChange" might interfere with the event handler.

  • TextChanged is invoked only, when the text box looses the focus.

bender
good question. at first I thought this was the problem - that I had simply not added the controls to the Controls collection, but sadly (I guess), I am. See the `AddConfigurationOption` methods I added above.
Ben Collins
Turns out I wasn't setting the ID of the editorpart. Once I set that, events started working. I'll mark yours as the answer because you helped me think through all those mechanics, even if you didn't mention that one specifically.
Ben Collins