Как сделать свойство декларируемым как любой наследуемый тип в разметке ASP.NET? - PullRequest
2 голосов
/ 03 февраля 2010

Я видел различные элементы управления в ASP.NET с «коллекциями» объектов, которые можно использовать для определения разметки. Например:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <Triggers>
        <asp:PostBackTrigger ControlID="MyButton" />
    </Triggers>
...
</asp:UpdatePanel>

В приведенном выше примере вы можете добавить любое количество триггеров, и они могут быть любого типа, расширяющего UpdatePanelTrigger. Я хотел бы сделать что-то подобное, но только с одним предметом вместо коллекции:

<app:PortalLink ID="DrinkLink" Text="I am thirsty">
    <portal:ViewProductsRequest ProductCategory="Drinks" />
</app:PortalLink>
--or--
<app:PortalLink ID="DrinkLink">
    <Content>I am thirsty</Content>
    <Request>
        <portal:ViewProductsRequest ProductCategory="Drinks" />
    </Request>
</app:PortalLink>

Идея состоит в том, что Запросу может быть предоставлен один объект любого типа, который наследует определенный интерфейс или класс. Есть ли способ сделать это?

Обновление

Чтобы уточнить, я хочу, чтобы PortalLink мог принимать все, что является подклассом запроса, который представляет параметры, которые принимает определенная страница. Например:

public class AdminMenuRequest : Request
{} // No parameters for the main menu page.
public class ViewProductsRequest : Request
{
    public string ProductCategory {get;set;}
    public bool? ShowOutOfStock {get;set;}
}

А в разметке:

<app:PortalLink runat="server" Text="I am an administrator">
    <portal:AdminMenuRequest />
</app:PortalLink>
<app:PortalLink runat="server" Text="I am thirsty">
    <portal:ViewProductsRequest ProductCategory="Drinks" />
</app:PortalLink>

До сих пор я выяснил, что я могу либо сделать элементы управления Requests для себя, либо заставить PortalLinks принимать набор запросов (но не ограничиваться одним запросом). Если я создаю элементы управления Requests, это как бы нарушает одноцелевое правило: запросы представляют собой как запрос на стороне сервера, так и ссылку на стороне клиента. Плюс, так как я хочу иметь один запрос на «страницу», в большинстве случаев это также приведет к загрязнению списка intellisense. Если я заставлю PortalLinks принимать коллекцию запросов, я могу просто использовать первый элемент в списке и игнорировать остальные. Это работает, но было бы неплохо иметь возможность обеспечить, чтобы у каждого PortalLink было одно (и только одно) значение. Также было бы легче при создании или инициализации ссылок в коде позади сказать:

((ViewProductsRequest)FoodOrDrinkLink.Request).ShowOutOfStock = OOSCheckBox.Checked;

Это то, что я могу подделать с дополнительными свойствами, но я надеялся на что-то более элегантное.

Ответы [ 2 ]

2 голосов
/ 03 февраля 2010

Посмотрите здесь: Пример свойства коллекции веб-элементов управления

РЕДАКТИРОВАТЬ: Для "простого" свойства вам не нужно ничего другого, кроме как создавать открытое свойство в вашем классе управления, но вы должны использовать его позже как атрибут тега как внутреннее свойство):

public partial class UCSample : UserControl
{
    public string MyCustomProperty { get; set; }

    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Write(this.MyCustomProperty);
    }
}

<%@ Page Language="C#"  %>
<%@ Register src="UCSample.ascx" tagname="UCSample" tagprefix="uc1"%>

<uc1:UCSample ID="UCSample1" runat="server" MyCustomProperty="StackOverflow" />
0 голосов
/ 05 февраля 2010

Вы можете использовать ControlBuilder для достижения этой цели.

Вот код, который я использовал:

public class PortalLinkBuilder : ControlBuilder {
  public override Type GetChildControlType(string tagName, IDictionary attribs) {
    // you need the full name of the types, suppose they're on namespace Portal
    return Type.GetType("Portal." + tagName, true);
  }
  public override void AppendLiteralString(string s) {
    // ignores literals between rows
  }
}

[ControlBuilder(typeof(PortalLinkBuilder))]
public class PortalLink : Control {

  protected override void AddParsedSubObject(object obj) {
    if (Request != null) throw new InvalidOperationException("Too many requests!");
    Request = (Request)obj; // will fail for non-Request objects
  }

  [Browsable(false)] 
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public Request Request { get; private set; }

  ...

}

В пользовательском интерфейсе:

    <app:PortalLink runat="server" ID="lnk1">
        <AdminMenuRequest /> 
    </app:PortalLink>

    <app:PortalLink runat="server" ID="lnk2">
        <ViewProductsRequest ProductCategory="Drinks" />     
    </app:PortalLink>

Мне удалось заставить его работать, но дизайнерская поверхность жалуется на дочерние теги. Возможно, ваша идея о создании элементов управления Request исправит это, но вы должны также поддерживать свою семантическую модель отдельно от элементов управления и использовать элементы управления для построения модели. У вас были бы эти классы:

Модель:

  • Request
  • AdminMenuRequest
  • ViewProductsRequest

Органы управления:

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