代码之家  ›  专栏  ›  技术社区  ›  noocyte

是否可以在另一个web部件中加载web部件?

  •  11
  • noocyte  · 技术社区  · 17 年前

    所以,这就是我们想要做的:我们想要有一个通用的web部件,它周围有一个自定义的框架,然后在其中动态加载其他web部件(无框架)。你认为这可能吗?有点像 Jan Tielens SmartPart ,不仅适用于ASP.Net用户控件,还适用于其他Web部件…;)

    编辑:我们现在已经可以这样做了。解决方案其实相当简单。查看代码:

    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);
        }
    }
    

    就这么简单。。。我们还使用反射将Web部件存储为Xml等,但这并不是重点。

    5 回复  |  直到 17 年前
        1
  •  4
  •   Steven Robbins    17 年前

    我不这么认为。我之前试过这个,它抱怨只能在PageInit中添加WebPartZone项目。我认为当你开始初始化你的“容器”网页时,添加更多的区域已经太迟了,因为等待页面已经初始化了。

        2
  •  4
  •   noocyte    16 年前
    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);
        } 
    }
    

    1. parentWebPartGuid-这是托管Web部件的Guid(UniqueId?)。出于某种原因,我们必须使用反射(它是私有属性)将“StorageKeyInternal”设置为此值。你可以不设置它,但至少对于大多数Web部件,我们必须设置它。

    2. Properties-这是配置值(我们在一个自定义的.xml文件中设置它们,但是可以从任何地方获取)。它看起来有点像 this ..

    在我们的框架中,我们还支持动态属性值等内容,但这是另一天的事情。。。希望这一切都是有意义的,可以帮助别人。

        3
  •  2
  •   PhiLho    17 年前

    [注]我的回答是一般性的(即网页设计方面),我不知道在你们的技术背景下如何回答,所以也许我应该删除这个答案。。。

        4
  •  2
  •   Tyler    16 年前

    没有机会获得WebPartFactory类的源代码吗?或者再多了解一点?可能是伪代码?如果库中有自定义web部件,则可以使用与RSSViewer相同的方式引用该部件是否正确?我只是不知道如何去做你在这里所做的事情,我非常想更好地理解如何去做。

    谢谢

        5
  •  0
  •   Ewerton    12 年前

    当一个用户想要在另一个自定义Web部件中实例化一个自定义Web部件时,我在.ascx中使用以下代码

    <%@ Register tagPrefix="uc1" Namespace="Megawork.Votorantim.Intranet.Webparts_Intranet.LikeButton" Assembly="Megawork.Votorantim.Intranet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=769156d154035602"  %>
    

    当我想要实例化它时,通常(事实上)是在.cs中使用以下代码

    //This is the namespace of the control that will be instantiated dinamically    
    string type = "My.Custom.Namespace.WebpartToBeAdded.WebpartToBeAdded";
    
    // Instantiate the control dinamically based on his type
    System.Web.UI.WebControls.WebParts.WebPart genericWP = (System.Web.UI.WebControls.WebParts.WebPart)Activator.CreateInstance(Type.GetType(type));
    
    // sets the page to the genericWP (i dont know if this is required)
    genericWP.Page = this.Page;
    
    // Note: if you want to call custom methods of the dinamically instantiated controls (like a custom load method) you will need to create an interface and make your dinamically instantiated webpart implement it. You will need to do it in that file that have the following code: private const string _ascxPath @"~/_CONTROLTEMPLATES/...". Then you can do the following
    //IMyInterface ig = (IMyInterface)genericWP;
    //ig.MyCustomLoadMethod(someParam);
    
    // Adds the controls to a container, an asp panel by example.
    panelDinamicControls.Controls.Add(genericWP);