可以将一个 Web 部件加载到另一个 Web 部件中吗?

发布于 2024-07-10 22:21:32 字数 654 浏览 7 评论 0原文

因此,这就是我们想要做的:我们想要一个通用的 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 等,但这不是重点。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

椵侞 2024-07-17 22:21:32

我不这么认为。 我不久前尝试过此操作,但它抱怨只能在 Page Init 中添加 WebPartZone 项目。 我认为当初始化“容器”WebPart 时,添加更多区域为时已晚,因为保留页面已经初始化。

I don't think so. I tried this a while back and it complained about only being able to add WebPartZone items in Page Init. I think by the time it get's to initialising your "container" WebPart it's too late to add more zones as the holding page has already been initialised.

不弃不离 2024-07-17 22:21:32
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 的容器,只是一堆属性。 我想更详细地讨论 2 个问题:

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

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

..我们的框架还支持动态属性值等内容,但那是另一天的事了......希望这一切都有意义并且可以帮助某人。

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.

蓝天 2024-07-17 22:21:32

有(至少)两种方法可以做到这一点:使用 iframe HTML 元素,或者只是一个由 JavaScript 更改内容的 div(可能使用 Ajax)。

[注意]我的答案是通用的(即在网页设计方面),我不知道它在您的技术背景下如何,所以也许我应该删除这个答案......

There are (at least) two ways to do this: using iframe HTML element, or just a div whose content is changed by JavaScript (probably with Ajax).

[NOTE] My answer is generic (ie. on Web design side), I have no idea how it in your technical context, so maybe I should delete this answer...

染火枫林 2024-07-17 22:21:32

没有机会获取 WebPartFactory 类的源代码吗? 或者也许有更多关于它的信息? 也许是伪代码? 如果自定义 Web 部件位于库中,则可以按照与 RSSViewer 相同的方式进行引用,正确吗? 我只是不太确定如何去做你在这里所做的事情,我非常想更好地了解如何做到这一点。

谢谢!

No chance on getting the source for the WebPartFactory class is there? Or maybe a bit more information about it? Pseudo code maybe? If a custom web part is in the gallery it could be referenced in the same way as RSSViewer is correct? I'm just not really sure how to go about doing what you have done here, and I would very much like to better understand how to do this.

Thanks!

悟红尘 2024-07-17 22:21:32

当想要在另一个自定义 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);

When a want to instantiate a custom webpart inside another custom webpart i use the following code in the .ascx

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

The Namespace value and the Assembly value can be copied from the SafeControls line from the webconfig or from the package file (in manifest tab) :)

When i want to instantiate it dinammicaly (in fact) is use the following code in the .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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文