views:

226

answers:

2

The current project I'm working on allows UserControls to be dynamically added to a page in a number of different placeholders across what could be an infinite number of templates. So basically using a CMS.

Awesome I hear you say but what happens when I want two of these UserControls to talk to each other? i.e. A search form control and a search results control. This was the problem I tackled recently and came up with a solution I'm reasonably happy with but thought I'd float it out there and see what you all think.

Firstly, I quickly decided to ignore the FindControl method, any solution I could think of involving it got messy and made me die a little inside.

EDIT: The decision to not use FindControl is due to the fact it only searches through the Control's child control collection and thus would require looping through controls to find the one I want.

This is what I have so far: Added a global public property to my base page class called BasePage:

public SortedList<string, CustomUserControl> CustomControls { get; set; }

Added a public property to my base user control class called CustomUserControl:

protected SortedList<string, CustomUserControl> CustomControls
{
    get 
    {
        BasePage page = Page as BasePage;
        if (page != null)
            return page.CustomControls;
        else
            return null;
    }
}

On the Page_Init of my UserControls added a reference to the control to the CustomControl collection, which assigns it to the property of the BasePage.

I can then access my UserControls from either the Page or the controls themselves using the CustomControl method, like such:

if (this.CustomControls.ContainsKey("SearchForm"))
    searchForm = this.CustomControls["SearchForm"] as SearchForm;

Thats the basics of it, am refining it as write this so please feel free to pick it apart. If any of you have a better/alternative solution I'd love to hear it. Or even if you've read an article on the problem, Google didn't help me much in my searches.

A: 

I don't understand your reluctance to use FindControl. Think about how Microsoft solved this exact same problem... Specifically, the validator controls. They just have a property called ControlToValidate that takes another control's ID as a string. Internally, it probably just uses FindControl. (well, honestly I don't know, but it seems a likely bet)

Your solution seems somewhat redundant, because the Page object already has a collection of all the controls. And it only works in your specific context.

Edit: BTW, I just looked at the built-in validators and they do indeed just use FindControl. Maybe I am misunderstanding something about your requirements.

Bryan
I though the collection of controls in the Page object only contains its child controls, and those controls then contain their child controls and so on. To retrieve a control via this method you would have to iterate through all the collections until you find the control your after.Not sure on the ControlToValidate either but it does make sense that it would use the FindControl method, is it capable of validating accross different Controls/Pages though?
philba888
Hmmmm... it seems in the case of validators they only work with controls in the same NamingContainer. I guess you'd have the same issue here. What you could probably do is just grab the parent or Page property and call FindControl from there.
Bryan
As I have a number of layouts and sublayouts where the controls can be added anywhere the FindControl method isn't as useful as it only searches through the Control's child control collection, not the entire hierarchy. So I would have to loop through controls until I found the control I was after.
philba888
A: 

As you say, FindControl only looks at a containers immediate children, so you would have to loop over them all to find a control. Why is this a problem? If you make the function recursive the whole thing ends up being only a handful of lines of code. If you make it an extension to the Control class you then have handy access to the function.

For example:


    public static class ControlExtensions
    {
        public static Control FindControl(this Control control, string id, bool Recursive)
        {
            var result = control.FindControl(id);
            if (!Recursive) return result;
            if (result == null)
            {
                foreach (Control child in control.Controls)
                {
                    result = child.FindControl(id, true);
                    if (result != null) return result;
                }
            }
            return null;
        }
    }

Mr Bell
Note: if there are multiple instances of controls with the same id, this will return the first one it finds. But it sounds like that isn't a problem in your case.
Mr Bell