Как загрузить пользовательский элемент управления, учитывая его тип - PullRequest
1 голос
/ 05 марта 2011

Есть ли способ создать экземпляр и использовать usercontrol (.ascx), если у вас есть его тип (то есть. typeof(MyUserControl))?

С помощью обычных элементов управления asp.net, таких как текстовое поле или выпадающий список, вы можете просто создать новый экземпляр и добавить его в коллекцию элементов управления. Это не работает для пользовательских элементов управления. Хотя вы можете создать новый экземпляр и добавить его в коллекцию, и все его события будут запущены, он фактически не будет отображаться на странице. Обычно вы вызываете Page.LoadControl() с путем к .ascx

Это создает проблему, если у вас есть только его тип. Как вы можете получить путь к .ascx, чтобы дать метод LoadControl. В идеале я также хотел бы, чтобы не было ссылки на объект Page

Ответы [ 3 ]

3 голосов
/ 01 октября 2012

Нет. Это не возможно; виртуальный путь ASCX должен быть предоставлен для динамической загрузки пользовательского элемента управления с разметкой, и внутреннее отображение типов виртуальных путей отсутствует.

Однако, поскольку я все еще ленивый , здесь я использовал подход, который все еще является "безопасным для типов", и изолирует решение проблемы в одном месте в коде. Он по-прежнему требует доступа к «объекту страницы», но в остальном заботится о глупых деталях.

Вот краткое объяснение:

  1. Используйте type , чтобы найти относительный (к моему корню) путь ASCX, используя эвристику для отображения типов из пространства имен в виртуальный путь; разрешить способ указания ручного отображения и использовать его, если указано
  2. Превратить относительный путь типа в правильный / полный виртуальный путь
  3. Загрузка элемента управления с помощью виртуального пути
  4. Продолжайте, как будто ничего не произошло

Наслаждайтесь (я просто копирую и вставляю отдельные части из моего проекта, YMMV):

    /// <summary>
    /// Load the control with the given type.
    /// </summary>
    public object LoadControl(Type t, Page page)
    {
        try
        {
            // The definition for the resolver is in the next code bit
            var partialPath = resolver.ResolvePartialPath(t);
            var fullPath = ResolvePartialControlPath(partialPath);
            // Now we have the Control loaded from the Virtual Path. Easy.
            return page.LoadControl(fullPath);
        } catch (Exception ex)
        {
            throw new Exception("Control mapping failed", ex);
        }
    }

    /// <summary>
    /// Loads a control by a particular type.
    /// (Strong-typed wrapper for the previous method).
    /// </summary>
    public T LoadControl<T>(Page page) where T : Control
    {
        try
        {
            return (T)LoadControl(typeof (T), page);
        } catch (Exception ex)
        {
            throw new Exception(string.Format(
                "Failed to load control for type: {0}",
                typeof (T).Name), ex);
        }
    }

    /// <summary>
    /// Given a partial control path, return the full (relative to root) control path.
    /// </summary>
    string ResolvePartialControlPath(string partialPath)
    {
        return string.Format("{0}{1}.ascx",
            ControlPathRoot, partialPath);
    }

Список кодов для ControlResolver:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FooBar
{
    class ControlResolver
    {
        const string BaseNamespace = "TheBaseControlNameSpace";

        readonly IDictionary<Type, string> resolvedPaths = new Dictionary<Type, string>();

        /// <summary>
        /// Maps types to partial paths for controls.
        /// 
        /// This is required for Types which are NOT automatically resolveable
        /// by the simple reflection mapping.
        /// </summary>
        static readonly IDictionary<Type, string> MappedPartialPaths = new Dictionary<Type, string>
        {
            { typeof(MyOddType), "Relative/ControlPath" }, // No virtual ~BASE, no .ASXC
        };

        /// <summary>
        /// Given a type, return the partial path to the ASCX.
        /// 
        /// This path is the path UNDER the Control Template root
        /// WITHOUT the ASCX extension.
        /// 
        /// This is required because there is no mapping maintained between the class
        /// and the code-behind path.
        /// 
        /// Does not return null.
        /// </summary>
        public string ResolvePartialPath (Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            string partialPath;
            if (resolvedPaths.TryGetValue(type, out partialPath))
            {
                return partialPath;
            } else
            {
                string mappedPath;
                if (MappedPartialPaths.TryGetValue(type, out mappedPath))
                {
                    resolvedPaths[type] = mappedPath;
                    return mappedPath;
                } else
                {
                    // Since I use well-mapped virtual directory names to namespaces,
                    // this gets around needing to manually specify all the types above.
                    if (!type.FullName.StartsWith(BaseNamespace))
                    {
                        throw new InvalidOperationException("Invalid control type");
                    } else
                    {
                        var reflectionPath = type.FullName
                            .Replace(BaseNamespace, "")
                            .Replace('.', '/');
                        resolvedPaths[type] = reflectionPath;
                        return reflectionPath;
                    }
                }
            }
        }
    }
}
0 голосов
/ 23 апреля 2019
  ' Load the control 
  Dim myUC as UserControl = LoadControl("ucHeading.ascx") 

  ' Set the Usercontrol Type 
  Dim ucType as Type = myUC.GetType() 

  ' Get access to the property 
  Dim ucPageHeadingProperty as PropertyInfo = ucType.GetProperty("PageHeading") 

  ' Set the property 
  ucPageHeadingProperty.SetValue(myUC,"Access a Usercontrol from Code Behind",Nothing) 

  pnlHeading.Controls.Add ( myUC ) 
0 голосов
/ 05 марта 2011

Вам может не повезти.

Этот парень не смог получить помощь в этом.

И они сказали этому человеку , что это невозможно сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...