1

さまざまなタイプのオブジェクトのリストをループするリピーターがあります。オブジェクトの種類に応じて、オブジェクトを異なる方法でレンダリングしたいと思います。このためには、switch/case ステートメントに似た動作をするある種の制御が必要です (コード ビハインドの使用を避けたいため)。基本的には次のようになります。

<xxx:TestType Object='<%# Container.DataItem %>'>
    <Case Type="Namespace.ClassX">
        <asp:Label ... />
    </Case>
    <Case Type="Namespace.ClassY">
        <asp:TextBox ... />
    </Case>
    <Default>
        <p>Other</p>
    </Default>
</xxx:TestType>

以前に Web コントロールを作成したことがありますが、これはかなり複雑なものです...

  • <Case>複数の要素をサポートするにはどうすればよいですか?
  • 要素を実装することは可能<Case Type="...">ですか、それとも属性のない要素に限定されますか?

<Case>要素の型を作成し、それをメインの Web コントロールに指定する必要があると思いますか?

ポインタ、チュートリアルへのリンクなどに感謝します!

または、現在バインドされているオブジェクトのタイプに基づいて、さまざまな HTML/ASP.NET コントロールをレンダリングするより良い方法を提案してください。私の頭に浮かんだ最初の方法はこれでした。これは(非常に)醜いと思います:

<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassX)) %>' runat="server">
...
</asp:PlaceHolder>
<asp:PlaceHolder Visible='<%# CheckType(Container, typeof(ClassY)) %>' runat="server">
...
</asp:PlaceHolder>
4

5 に答える 5

1

ITemplate インターフェイスの実装を見てください

  public class Case        
    {

        [PersistenceMode(PersistenceMode.Attribute)]
        public string Type { get; set; }

        [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public ITemplate Template { get; set; }

    }

    public class DeclarativeCase
        : CompositeControl
    {
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public List<Case> Cases { get; set; }

        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate Default { get; set; }
    }

<xxx:DeclarativeCase runat="server" ID="test">
  <Cases>
   <xxx:Case Type="Namespace.TypeName">
    <Template>
     <asp:Label ID="Label1" runat="server"></asp:Label>
    </Template>
   </xxx:Case>
  </Cases>

<Default>
 <asp:Label ID="Label2" runat="server"></asp:Label>
</Default>

</xxx:DeclarativeCase>
于 2009-09-21T09:47:39.457 に答える
1

MultiViewコントロールは、ASP.NET ですぐに使用できる C# の switch ステートメントに最も近いものです。

于 2009-09-21T09:27:02.413 に答える
0

サーバー コントロールを捨てて、C# の switch ステートメントを使用してみませんか。コードタグでラップするだけです。

もう 1 つのアプローチは反復 (for ループ) です。type プロパティと render メソッドを使用してインターフェイスを作成します。次に、正しいタイプが見つかるまでインターフェイスを繰り返します。

于 2009-09-21T09:06:10.473 に答える
0

MSDNサイトには、テンプレートの単純で明確な例があり、あなたのケースでは確かにその方法のようです。

于 2009-09-21T19:37:29.303 に答える
0

少し前に同様の要件があり、次のようなことをしました。

[ParseChildren(true, "Templates")]
public class TypedRepeater : CompositeDataBoundControl
{
    [
    PersistenceMode(PersistenceMode.InnerProperty),
    Browsable(false),
    MergableProperty(false)
    ]
    public TypedTemplateCollection Templates
    {
        get;
    }

protected TypedTemplate GetTemplate(オブジェクト dataItem) { if (dataItem == null) { return null; } foreach (テンプレートの TypedTemplate テンプレート) { Type itemType = dataItem.GetType(); if (dataItem.IsAssignableFrom(template.Type)) { テンプレートを返します。null を返します。}

    protected TypedTemplateRepeaterItem CreateItem(int index, object dataItem, bool dataBinding)
    {
        TypedTemplateRepeaterItem repeaterItem = new TypedTemplateRepeaterItem();
        if ((!dataBinding) && (ViewState[string.Format("TemplateIxc_{0}", index)] is int))
        {
            int _template = (int)ViewState[string.Format("TemplateIxc_{0}", index)];
            if ((_template >= 0) && (_template < Templates.Count) && (Templates[_template].ItemTemplate != null))
            {
                Templates[_template].ItemTemplate.InstantiateIn(repeaterItem);
            }
            else
            {
                DefaultTemplate.InstantiateIn(repeaterItem);
            }
        }
        else if (dataBinding)
        {
            TypedTemplate template = GetTemplate(dataItem);
            ITemplate itemTemplate = DefaultTemplate;
            if (template != null)
            {
                itemTemplate = template.ItemTemplate;
                ViewState[string.Format("TemplateIxc_{0}", index)] = Templates.IndexOf(template);
            }
            else
            {
                ViewState[string.Format("TemplateIxc_{0}", index)] = -1;
            }

            repeaterItem.DataItem = dataItem;
            repeaterItem.DataItemIndex =
                repeaterItem.DisplayIndex = index;
            itemTemplate.InstantiateIn(repeaterItem);
            repeaterItem.DataBind();
            repeaterItem.DataItem = null;
        }
        return repeaterItem;
    }

    protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
    {
        int count = 0;
        if (dataSource != null)
        {
            foreach (object dataItem in dataSource)
            {
                TypedTemplateRepeaterItem repeaterItem = CreateItem(count, dataItem, dataBinding);      
                Controls.Add(repeaterItem);
                count++;
            }
        }
        return count;
    }
}

ここで、TypedTemplateCollection は TypedTemplate クラスの StateManagedCollection です。

[ParseChildren(true, "ItemTemplate")]
public class TypedTemplate
{

    public Type Type
    {
        get { return Type.GetType(TypeName); }
    }

    [
    PersistenceMode(PersistenceMode.Attribute),
    Browsable(true),
    DefaultValue("")
    ]
    public string TypeName
    {
        get;
        set;
    }

    [
    PersistenceMode(PersistenceMode.InnerProperty),
    Browsable(true),
    DefaultValue(typeof(ITemplate), null),
    TemplateContainer(typeof(TypedTemplateRepeaterItem))
    ]
    public ITemplate ItemTemplate
    {
        get;
        set;
    }
}

TypedTemplateRepeaterItem は次のとおりです。

public class TypedTemplateRepeaterItem : WebControl, INamingContainer, IDataItemContainer
{
    #region IDataItemContainer Members

    public object DataItem
    {
        get;
        set;
    }

    public int DataItemIndex
    {
        get;
        set;
    }

    public int DisplayIndex
    {
        get;
        set;
    }

    #endregion
}
于 2009-09-21T09:29:53.393 に答える