Можно ли загрузить веб-часть внутри другой? - PullRequest
11 голосов
/ 07 января 2009

Итак, вот что мы хотим сделать: мы хотим иметь общую веб-часть с настраиваемой рамкой вокруг нее, а затем динамически загружать другие веб-части (без рамки) внутри нее. Это вообще возможно, вы думаете? Немного похоже на Jan Tielens SmartPart , только не для пользовательских элементов управления ASP.Net, а для других веб-частей ...;)

Редактировать: мы смогли сделать это сейчас. Решение было на самом деле довольно простым. Проверьте код:

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

Это просто ... Мы также используем отражение для хранения веб-частей в формате XML и т. Д., Но это не относится к делу.

Ответы [ 5 ]

4 голосов
/ 12 февраля 2009
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", это просто контейнер для настройки веб-частей, просто набор свойств. Есть 2 вопроса, которые я хотел бы обсудить более подробно:

  1. parentWebPartGuid - это Guid (уникальный идентификатор?) Веб-части хостинга. По какой-то причине мы должны установить «StorageKeyInternal» на это значение, используя отражение (это частное свойство). Вы можете обойтись без настройки, но, по крайней мере, для большинства веб-частей мы должны были установить его.

  2. config.Properties - это значения конфигурации (мы устанавливаем их в пользовательский файл .xml, но вы можете получить его из любого места). Это может выглядеть как this ..

В нашем фреймворке мы также поддерживаем такие вещи, как значения динамических свойств и т. Д., Но это на другой день ... Надеюсь, все это имеет смысл и может кому-нибудь помочь.

4 голосов
/ 07 января 2009

Я так не думаю. Я пытался это сделать некоторое время назад, и он жаловался только на то, что мог добавлять элементы WebPartZone в Page Init. Я думаю, что к моменту инициализации вашей «контейнерной» веб-части уже слишком поздно добавлять новые зоны, поскольку удерживающая страница уже инициализирована.

2 голосов
/ 24 ноября 2009

Нет шансов получить исходный код для класса WebPartFactory? Или, может быть, немного больше информации об этом? Может быть, псевдокод? Если пользовательская веб-часть находится в галерее, на нее можно ссылаться так же, как правильно использовать RSSViewer? Я просто не совсем уверен, как делать то, что вы сделали здесь, и я очень хотел бы лучше понять, как это сделать.

Спасибо!

2 голосов
/ 07 января 2009

Есть (как минимум) два способа сделать это: использовать элемент iframe HTML или просто div, содержимое которого изменяется с помощью JavaScript (возможно, с помощью Ajax).

[ПРИМЕЧАНИЕ] Мой ответ является общим (т.е. на стороне веб-дизайна), я понятия не имею, как он в вашем техническом контексте, поэтому, возможно, мне следует удалить этот ответ ...

0 голосов
/ 15 апреля 2014

Когда требуется создать экземпляр пользовательской веб-части внутри другой пользовательской веб-части, я использую следующий код в .ascx

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

Значение пространства имен и значение Assembly можно скопировать из строки 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);
...