0
votes

A Bit of Background:

I have been working on a custom data type for Umbraco. The datatype displays a list of nodes of a particular type and allows the user to select from this list. I have attempted to make this data type reusable so that I do not have to create a separate one for each type of node I wish to list. I simply create a property of this data type and set which type of nodes to display.

The datatype is an UpdatePanel that contains of a list of checkboxes (for each node to select) and a button to Add/Remove these nodes to and from the selection.

As an example, if I have a Post, i can add this datatype and set it to list categories, this allows me to associate the post with a list of categories. If i then want to have another instance of this datatype, say to pick Authors, I start running into issues.

DataType Structure Information

This should give some more detail into how this control is built. It used the 3 classes method of creating an umbraco datatype so I do not have a .ascx file, just a .cs file that programatically renders elements onto the page.

The checkboxes are rendered by iterating through a list of Nodes and rendering the following:

<input type='checkbox' name='select_nodes' value='" + n.Id + "' />

I then render two buttons, one to add the nodes to the list of selected nodes, and one to remove them (I am just showing add here). This button simply gets the value of Form["select_nodes"] which contains a comma separated list of node Ids, and for each one, adds it to the list of separate nodes.

The buttons are added as follows:

public override void OnInit(EventArgs e)
{
    //Add Button
    btn_Add = new Button();
    btn_Add.CssClass = "btn_add";
    btn_Add.ID = "btnAdd" + Guid.NewGuid();
    btn_Add.Text = "Add >>";
    btn_Add.Click += new EventHandler(selectNodes);
    base.ContentTemplateContainer.Controls.Add(btn_Add);
}

The above describes this control in its basic form, and hopefully provides a bit more insight into the setup.

The Issue

On loading a node with multiple instances of this datatype, as in the example above, errors occur due to duplicate control ids, I overcame this by appending a random guid to the ids. The problem now is that the buttons to select/deselect the nodes do not appear to be working. I'm assuming it is due to there being multiple instances of these buttons, and getting confused with which event to fire?

Is there a way to get around this? To avoid interference across multiple instances of a control?

Thanks,

3
Are these items in a databound item such as a repeater or a DataGrid? If so, you can simply intereact with the row that triggered the event, and use FindControl() to find the checkbox in the Button_Click event. Working code can be found at dreamincode.net/forums/topic/… If you need additional data, store it in HiddenFields, and access it the same way.David
Thanks David, I have added some extra information about how the control is set up. I am currently not using a databound item, but will take a look at the link you have given and investigate options. In the mean time, hopefully the extra info will help. Thankscast01
This is meant to be helpful, not snooty... But reading it, I think I sound snooty, and I apologize, but here it is: The simplest way around it would be to change it. Don't generate the controls in code-behind. Use a Repeater or a ListView to do it. Microsoft has taken almost all the pain out of doing it, if you use the tools they provide.David
Thanks David, it came across fine :) i do appreciate the help and understand what you are saying. I prefer to keep the code and rendering separate and use .ascx files but It seems that I have to create the controls this way for better for integration with Umbraco (doing this allows the end user to set properties for these datatypes through the CMS, among other things).cast01
@David, there is no user control (ascx) file being used, therefore everything has to be generated with code.Douglas Ludlow

3 Answers

1
votes

I think the issue is your controls are generated again each time your page posts back, and they end up with a different ID because of the Guid.NewGuid() that gets appended each time. When the page posts back it runs a findcontrol for the button you clicked and then gets the event handler from that, but if the button's ID has changed it won't find it and subsequently doesn't find it's event handler.

The best way to get this kind of situation to work is not to generate a random string to append to the control name but to use a known constant that you can control within the context of the button creation. So if it is a button for list items you append "li" to it every time, or something like that. Then you know on every postback your control has the same name - but still unique to it's own instance.

0
votes

Success

As @Infotekka pointed out in the comments below:

I think the issue is your controls are generated again each time your page posts back, and they end up with a different ID because of the Guid.NewGuid() that gets appended each time. When the page posts back it runs a findcontrol for the button you clicked and then gets the event handler from that, but if the button's ID has changed it won't find it and subsequently doesn't find it's event handler

In response this, I replaced:

btn_Add.ID = "btnAdd" + Guid.NewGuid();

with

btn_Add.ID = "btnAdd_" + targetDocType.ToLower();

Following on from the example above, this results in one instance of this control/datatype with add/remove buttons with ids "btnAdd_Category" and "btnRemove_Category", and in the other instance ids "btnAdd_Author" and "btnRemove_Author".

Initially this did not fix the issue, but on further investigation, I had a LiteralControl that I was adding to the page to include some embedded css and this id also needed to be unique per instance.

Thanks @Infotekka for pointing out the root of the issue, and @dludlow for the links!

@Infotekka, if you post your comment from earlier as an answer, I can mark it as the answer :)