可以在另一个内部加载一个 Web 部件吗?
Posted
技术标签:
【中文标题】可以在另一个内部加载一个 Web 部件吗?【英文标题】:Possible to load a web part inside another? 【发布时间】:2010-09-29 23:55:31 【问题描述】:所以,这就是我们想要做的:我们希望有一个通用的 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);
就这么简单...我们还使用反射将 webparts 存储为 Xml 等,但这不是重点。
【问题讨论】:
这适用于简单的 Web 部件,但它适用于利用 Web 部件特定事物(如消费者/生产者等)的事物吗? 您说的是连接,对吗?我想是的,这只是设置正确的属性值的问题。但我没试过这个...... 您是否尝试过以这种方式加载内容编辑器 Web 部件?当我实例化一个时,即使在为 web 部件设置了存储密钥 Internal 之后,它似乎也无法使用...... 不,抱歉从未尝试过。可能对它有一些特殊要求。我建议您使用 Reflector 来查看在 SharePoint 实例化期间是否发生了任何特殊情况。 【参考方案1】:我不这么认为。我前一阵子尝试过,它抱怨只能在 Page Init 中添加 WebPartZone 项目。我认为在初始化“容器”WebPart 时,添加更多区域为时已晚,因为已经初始化了保存页面。
【讨论】:
我现在已经发现了如何做到这一点,并将更新我的帖子以显示这一点。 :)【参考方案2】: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);
这段代码需要解释一下……如果它不能编译,请原谅,我不得不删除相当多的原始代码,这是非常具体的实现内容。我也没有展示“config”类,它只是一个用于配置 webpart 的容器,只是一堆属性。我想更详细地讨论两个问题:
parentWebPartGuid - 这是托管 Web 部件的 Guid (UniqueId?)。出于某种原因,我们必须使用反射将“StorageKeyInternal”设置为这个值(它是一个私有属性)。您可以不设置它而侥幸逃脱,但至少对于大多数 Web 部件而言,我们必须设置它。
config.Properties - 这是配置值(我们在自定义 .xml 文件中设置它们,但可以从任何地方随意获取)。它可能看起来有点像this..
在我们的框架中,我们还支持动态属性值等内容,但那是另一天……希望这一切都有意义并且可以帮助某人。
【讨论】:
感谢您提供这个出色的解决方案 noocyte。我面临的问题是 WP 似乎不可编辑。当我打开工具窗格以设置提要 url 时,我看到此错误:“您尝试更改的 Web 部件无效或已被其他用户删除。刷新页面。”关于为什么会发生这种情况的任何想法? 不,抱歉,我不知道。从我的回答中可以看出,我写它已经快 6 年了,所以这种方法很有可能不再起作用。从那以后我也换过工作(两次!),所以我无法访问我们当时编写的代码......抱歉,我无法提供更多帮助。【参考方案3】:有(至少)两种方法可以做到这一点:使用 iframe html 元素,或者只是一个内容由 javascript 更改的 div(可能使用 Ajax)。
[注意] 我的答案是通用的(即在网页设计方面),我不知道它在您的技术背景下如何,所以也许我应该删除这个答案......
【讨论】:
【参考方案4】:没有机会获得 WebPartFactory 类的源代码吗?或者可能有更多关于它的信息?可能是伪代码?如果自定义 Web 部件在库中,它可以以与 RSSViewer 相同的方式引用它是否正确?我只是不确定如何去做你在这里所做的事情,我非常想更好地了解如何做到这一点。
谢谢!
【讨论】:
我们通过反射来做到这一点。所以你需要类型和程序集,然后你应该能够很好地加载它。但是有一些警告......我会尽快用一些代码更新我的答案。【参考方案5】:当想要在另一个自定义 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" %>
可以从 webconfig 中的 SafeControls 行或从包文件(在清单选项卡中)复制命名空间值和程序集值:)
当我想实例化它时(实际上)是在 .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);
【讨论】:
这段代码一直对我有用,我喜欢这种方式,因为实例化 webpart 的唯一要求是正确的命名空间,在某些情况下,我将它存储在共享点列表中,它变得真正动态化。跨度>以上是关于可以在另一个内部加载一个 Web 部件吗?的主要内容,如果未能解决你的问题,请参考以下文章
将 HTML 从内部文件添加到 SharePoint 上的 Web 部件
内部小部件树不能大于页面:一个小部件不能在一个页面上部分绘制,而其余部分在另一页面上:它是不可分割的
创建加载用户控件的 SharePoint 2013 Web 部件
我可以使 SharePoint 图像 Web 部件可单击以链接到另一个页面吗