Search code examples
sharepointweb-parts

Possible to load a web part inside another?


So, this is what we want to do: We want to have a generic web part with a custom frame around it and then dynamically load other web parts (frameless) inside it. Would this at all be possible you think? A bit like Jan Tielens SmartPart, only not for ASP.Net User Controls, but for other Web parts... ;)

Edit: We've been able to do this now. The solution was actually pretty simple. Check out the code:

public class WebPartWrapper : System.Web.UI.WebControls.WebParts.WebPart {
    protected override void CreateChildControls() {    
        Panel pnl = new Panel();
        this.Controls.Add(pnl);
        WebPart dynamicPart = WebPartFactory.CreateWebPart("RSSViewer");
        pnl.Controls.Add(dynamicPart);
    }
}

Easy as that... We also use reflection to store the webparts as Xml etc., but that's beside the point.


Solution

  • public class WebPartWrapper : System.Web.UI.WebControls.WebParts.WebPart {
        protected override void CreateChildControls() {    
            Panel pnl = new Panel();
            this.Controls.Add(pnl);
            var factory = new WebPartFactory()
            WebPart dynamicPart = factory.CreateWebPart("RSSViewer", this.Guid);
            pnl.Controls.Add(dynamicPart);
        }
    }
    
    public class WebPartFactory {
        public WebPart CreateWebpart(string webpartName, Guid parentWebPartGuid)
        {
            var config = ConfigurationFactory.LoadConfiguration(webpartName);
    
            Assembly webPartAssembly = Assembly.Load(config.Assembly);
            Type webPartType = webPartAssembly.GetType(config.Class);
            object actualWebPart = Activator.CreateInstance(webPartType);
    
            foreach (var item in config.Properties)
            {
                PropertyInfo webPartProperty = webPartType.GetProperty(item.Name);
                object webPartPropertyValue = Convert.ChangeType(itemValue, Type.GetType(item.Type));
                if (!String.IsNullOrEmpty(item.Value))
                    webPartProperty.SetValue(actualWebPart, webPartPropertyValue, null);
            }
    
            RunMethod("set_StorageKeyInternal", actualWebPart, new object[] { parentWebPartGuid });
            return actualWebPart as WebPart;
        }
    
        private void RunMethod(string methodName, object objectInstance, object[] methodParameters)
        {
            BindingFlags flags = BindingFlags.Instance | BindingFlags.Public |
                BindingFlags.NonPublic;
    
            Type t = objectInstance.GetType();
            MethodInfo m = GetMethod(t, methodName, flags);
            if (m != null)
            {
                m.Invoke(objectInstance, methodParameters);
            }
        }
    
        private MethodInfo GetMethod(Type instanceType, string methodName, BindingFlags flags)
        {
            MethodInfo m = instanceType.GetMethod(methodName, flags);
            if (m != null)
            {
                return m;
            }
    
            if (instanceType.GetType() == typeof(object) || instanceType.BaseType == null)
            {
                return null;
            }
    
            return GetMethod(instanceType.BaseType, methodName, flags);
        } 
    }
    

    This code needs some explaining... Please excuse me if it does not compile, I had to remove a fair bit of the original code, it was very implementation specific stuff. I've not shown the "config" class either, it's just a container for configuration of webparts, just a bunch of properties. There are 2 issues I'd like to discuss in more detail:

    1. parentWebPartGuid - This is the Guid (UniqueId?) of the hosting webpart. For some reason we have to set "StorageKeyInternal" to this value, using reflection (it's a private property). You can possibly get away with not setting it, but at least for the majority of webparts we had to set it.

    2. config.Properties - This is the config values (we set them in a custom .xml file, but feel free to get this from anywhere). It can look a little like this..

    In our framework we also support stuff like dynamic property values etc., but that's for another day... Hope this all makes sense and can help somebody.