0

I've developed a custom web part. With custom properties it loads an iframe along with other text.

Then i tried to add this web part twice on the same page everything works fine except the "preview" (onPreRender). Every time I change properties the page is refreshed (form submitted). Instead of the changes only affect the web part that I am editing..they affect all the other one too. But when I hit apply, each of the web parts is going to display to get the right properties and displays different content.

So the problem it's before applying. How can I guarantee that only the web part that I'm editing is going to be changed?

Some of my onPreRender code might help.

public string Parameter
    { 
        get { return parameter; } 
        set { parameter= value; } 
    }

protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        ClientScriptManager cs = Page.ClientScript;
        cs.RegisterClientScriptInclude(this.GetType(), "jq", "/_layouts/js/jquery.js");
        cs.RegisterClientScriptInclude(this.GetType(), "custom", "/_layouts/js/custom.js");

        if(!string.IsNullOrEmpty(this.Parameter)){
           // I do some stuff here using this.Parameter like adding text to elements
          // those elements are created on CreateChildControls()
        }
     }

This is ApplyChanges from my Custom Tool Part class

public override void ApplyChanges()
    {
        MyCustomWebPart wp = (MyCustomWebPart )this.ParentToolPane.SelectedWebPart;
        wp.Parameter= param.Text;
        base.ApplyChanges();
    }

On CreateChildControls() I do create some elements without content, and I fill them in with the code above. Before applying if I have more than one of this Web Part, after submitting the form to change properties all the web parts show the same text, after applying everything goes like it should.

1
  • I'm using Custom properties. It's on a different class and I set that parameter overriding ApplyChanges(). I'll update above but I don't think that's the issue because it's saving the parameter fine.
    – nhenrique
    Commented Oct 1, 2013 at 9:33

1 Answer 1

2

I can tell you where its going wrong!

its here:

    cs.RegisterClientScriptInclude(this.GetType(), "jq", "/_layouts/js/jquery.js");
    cs.RegisterClientScriptInclude(this.GetType(), "custom", "/_layouts/js/custom.js");

how do i know? well its simple! i presum as you said you have many instances of custom.js

now this is where it gets messy, to put it simple! i have created a webpart and it contains an ascx. The webpart is added 5 times to the page (its a textbox that moves up/down).

To move the textbox I added Javascript to it, now when i run the code i notice that all 5 textbox (webparts) move up and down at the same time even tho in my javascript it should be random! (each webpart is ment to move at random intervals from each other)

to explain whats going on! javascript doesnt know what control to move as what your passing is exactly the same! so if like in my exaple i have each textbox wraped in a div with its class or id as "moveme", in the js i said to find moveme and move it up/down. As the webparts are repeated 5 times that makes 5 divs with the same ID's "moveme" so that javascript code is moving all 5 divs with that id ;) , so do you get where im going?

to get around this issue and to target the selected webpart you need to assign a unqiue id or pass on the auto generated div to the js file!

http://forums.asp.net/t/1855866.aspx

in your case its passing the webparts id! what exactly are you doing in the js files? this is a common issue when it comes to multiple controls/webparts using the same JS file using the same ID/Class.

also make sure your controls that your setting have unique values;

you can use Random;

//call the random generator class
Random rnd = new Random();
//use the code below as the auto id generator for you
rnd.Next();

so the above code will be used in this sense:

Textbox tb = new Textbox();

tb.Id = rnd.Next();

leaving the controls without id set should be auto generated.

it looks like you have multiple controls for some reason with the same id! hence why your getting all the same controls being updated with the same content until you submit the page

you need to look at your js file to see what its doing client side that is putting in the same content though all other webparts. When you click the submit button that is different because the control ids are auto generated and the button is serverside and its related to that webpart not the others, so the button you click will only update the webpart it belongs to... the others loose the content as the event related to the other webparts are different!

so my conclusion is.... your js file is doing somthing it should. it just doesnt know what exact control to update on client side as its updating all the webparts indicating they all have the same class or id (could be a div, textbox ect).

one solution isto pass your id's to the correct place? like making a parent div. It would be unique for each webpart by incrementing by the value of 1 everytime a webpart is added. This value is then passed on to the js file to do what it needs todo! so it would look like this:

webpart 1 div Id="1"

webpart 2 div Id="2"

webpart 3 div Id="3"

in your create child controls you can add the div like so:

    //create a varible to store your unique ids
    private int ids;

    protected override void CreateChildControls()
    {
         //add a div with an id
         this.Controls.Add(new LiteralControl("<div id='" + ids + "'>"));

         //do your normal code
         //add other controls
         TextBox tb = new TextBox();
         tb.Text = "hell0" + ids;
         this.Controls.Add(tb);

         //close the div
         this.Controls.Add(new LiteralControl("</div>"));
    }

so this webpart is adding a textbox surrounded by a div with a unique ID

now you need to remember ids for each new webparts thats repeating to page like so:

    //save/get last known ID value to session state
    public string ControlIds
    {
        get
        {
            return Page.Session["ControlIds"] as string;
        }
        set
        {
            Page.Session["ControlIds"] = value;
        }
    }

now ammend createchildcontrols to add it to session state:

add this first:

            if (ControlIds != null)
            {
                ids = int.Parse(ControlIds);
            }

this check to see if its NOT null, null is when it first loads, if its not than populate the value from session state into the varible

            //create a random number
            Random rndID = new Random();

            //check if script value is already registered (needs to be unique)
            if (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), "test" + rndID.Next().ToString()))
            {
                   //register the js script: here im calling MoveImage in my JS file that takes a varible ID
                   Page.ClientScript.RegisterStartupScript(this.GetType(), "test" + rndID.Next().ToString(), "MoveImage(" + ids + ");", true);

                   //increment the id
                   ids++;

                   //add the current ID to session state
                   ControlIds = ids.ToString();
            }

so the full .cs code will be:

    //save/get last known ID value to session state
    public string ControlIds
    {
        get
        {
            return Page.Session["ControlIds"] as string;
        }
        set
        {
            Page.Session["ControlIds"] = value;
        }
    }

    protected override void CreateChildControls()
    {

            if (ControlIds != null)
            {
                ids = int.Parse(ControlIds);
            }

         //add a div with an id
         this.Controls.Add(new LiteralControl("<div id='" + ids + "'>"));

         //do your normal code
         //add other controls
         TextBox tb = new TextBox();
         tb.Text = "hell0" + ids;
         this.Controls.Add(tb);

         //close the div
         this.Controls.Add(new LiteralControl("</div>"));

            //create a random number
            Random rndID = new Random();

            //check if script value is already registered (needs to be unique)
            if (!Page.ClientScript.IsStartupScriptRegistered(this.GetType(), "test" + rndID.Next().ToString()))
            {
                   //register the js script: here im calling MoveImage in my JS file that takes a varible ID
                   Page.ClientScript.RegisterStartupScript(this.GetType(), "test" + rndID.Next().ToString(), "MoveImage(" + ids + ");", true);

                   //increment the id
                   ids++;

                   //add the current ID to session state
                   ControlIds = ids.ToString();
            }
    }

in your js file you can see that its passing the value by doing this:

function MoveImage(arg) { alert("this controls ID is "+arg);

}

within the js file you can now do what you want by going through the parent (div ID) to its siblings (only to that specific webpart)

sorry for the long winded code!

3
  • it seems a very good answer! I will try this and get back to you in a sec ! thank you very much
    – nhenrique
    Commented Oct 1, 2013 at 10:45
  • I've used your answer as a start to solve my issue and it worked fine. Thank you for your time!
    – nhenrique
    Commented Oct 2, 2013 at 9:43
  • no probs happy to help!
    – Ali Jafer
    Commented Oct 2, 2013 at 10:22

Your Answer

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

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