【问题标题】:ASP.NET maintain control state that has collection itemsASP.NET 维护具有集合项的控件状态
【发布时间】:2015-08-11 16:55:01
【问题描述】:

有趣。我有一个带有Contacts 集合的控件QuickContacts。当我声明Contacts 类型为List<Contact> 时,它工作得很好,但是当使用ContactsList<Contact> 这是一个实现IList<T> 的泛型时,它给出“解析器错误:类型'Controls.ContactList'1 [[Controls.Contact,控件, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' 没有名为 'Contact' 的公共属性。" 在这里,此代码与List<Contact> 完美配合

[DefaultProperty("Contacts"),
ParseChildren(true, "Contacts"),
ToolboxData("<{0}:QuickContacts runat=server></{0}:QuickContacts>")]
public class QuickContacts : WebControl
{
    private List<Contact> contactsList;

    [Category("Behavior"),
    Description("The contacts collection."),
    DesignerSerializationVisibility(
        DesignerSerializationVisibility.Content),
    PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public List<Contact> Contacts
    {
        get
        {
            if (contactsList == null)
            {
                contactsList = new List<Contact>();
            }
            return contactsList;
        }
    }

我想提供一个维护状态的Contacts 集合,因此我将使用List&lt;Contacts&gt; 替换为实现IList&lt;T&gt;, IStateManager 的自定义ContactsList。当使用IList&lt;T&gt; 而不是List&lt;T&gt; 时,它不起作用。这里是

public class ContactList<T> : IList<T>, IStateManager
{

然后我使用它如下:

[DefaultProperty("Contacts"),
ParseChildren(true, "Contacts"),
ToolboxData("<{0}:QuickContacts runat=server></{0}:QuickContacts>")]
public class QuickContacts : WebControl
{
    private ContactList<Contact> contactsList;

    [Category("Behavior"),
    Description("The contacts collection."),
    DesignerSerializationVisibility(
        DesignerSerializationVisibility.Content),
    PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public ContactList<Contact> Contacts
    {
        get
        {
            if (contactsList == null)
            {
                contactsList = new ContactList<Contact>();
            }
            return contactsList;
        }
    }

“解析器错误:类型 'Controls.ContactList'1[[Controls.Contact, Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' 没有名为 'Contact' 的公共属性。”
&lt;cc1:Contact Name=的解析器错误

<asp:Content ID="Content2" ContentPlaceHolderID="Main" runat="server">
    <cc1:QuickContacts ID="QuickContacts1" runat="server" BorderStyle="Solid" BorderWidth="1px">
        <cc1:Contact Name="someone" Email="someone@example.com"
        Phone="(555) 555-0100" />

我阅读了很多关于 List&lt;T&gt;IList&lt;T&gt; 的帖子,但这仍然没有回答问题。 List&lt;T&gt; 和实现 IList&lt;T&gt; 的类之间有什么区别导致此错误?

【问题讨论】:

    标签: asp.net generics collections custom-controls state


    【解决方案1】:

    这是答案,在 Microsoft http://referencesource.microsoft.com 审查 List&lt;T&gt; 实现时

    [DebuggerTypeProxy(typeof(Mscorlib_CollectionDebugView<>))]
    [DebuggerDisplay("Count = {Count}")]
    [Serializable]
    public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>
    {
    

    它也实现了System.Collections.IList。这就是重点。

    这是完整的工作代码。

    [DefaultProperty("Contacts"),
    ParseChildren(true, ChildrenAsProperties = true, DefaultProperty = "Contacts"),
    ToolboxData("<{0}:QuickContacts runat=server></{0}:QuickContacts>")]
    public class QuickContacts : WebControl
    {
        private StateManagedCollection<Contact> contactsList;
    
        [Category("Behavior"),
        Description("The contacts collection."),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerDefaultProperty)]
        public StateManagedCollection<Contact> Contacts
        {
            get
            {
                if (contactsList == null)
                {
                    contactsList = new StateManagedCollection<Contact>();
                }
                return contactsList;
            }
        }
    
        protected override void RenderContents(HtmlTextWriter writer)
        {
    
            Table t = CreateContactsTable();
            if (t != null)
            {
                t.RenderControl(writer);
            }
        }
    
        private Table CreateContactsTable()
        {
            Table t = null;
    
            if (contactsList != null && contactsList.Count > 0)
            {
                t = new Table();
    
                foreach (Contact item in contactsList)
                {
                    Contact aContact = item as Contact;
    
                    if (aContact != null)
                    {
                        TableRow row = new TableRow();
    
                        TableCell c1 = new TableCell();
                        c1.Text = aContact.Name;
                        row.Controls.Add(c1);
    
                        TableCell c2 = new TableCell();
                        c2.Text = aContact.Email;
                        row.Controls.Add(c2);
    
                        TableCell c3 = new TableCell();
                        c3.Text = aContact.Phone;
                        row.Controls.Add(c3);
    
                        t.Controls.Add(row);
                    }
                }
            }
    
            return t;
        }
    
        protected override void LoadViewState(object savedState)
        {
            if (savedState != null)
            {
                Pair p = savedState as Pair;
                base.LoadViewState(p.First);
                contactsList.LoadViewState(p.Second);
            }
        }
    
        protected override object SaveViewState()
        {
            Pair p = new Pair(base.SaveViewState(), contactsList.SaveViewState());
            return p;
        }
    
        protected override void TrackViewState()
        {
            base.TrackViewState();
            contactsList.TrackViewState();
        }
    }
    

    这里是 StateManagedCollection

        public class StateManagedCollection<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>, IStateManager
            where T : StateManagedClass, new()
    {
        private List<T> lst = default(List<T>);
        private Boolean isTrackingViewState = default(Boolean);
        private Boolean saveAll = default(Boolean);
    
        public StateManagedCollection()
        {
            lst = new List<T>();
            isTrackingViewState = false;
            saveAll = false;
        }
    
        public void SetMarked()
        {
            for (int i = 0; i < lst.Count; i++)
            {
                lst[i].SetMarked();
            }
        }
    
        public bool IsTrackingViewState
        {
            get { return isTrackingViewState; }
        }
    
        public void LoadViewState(object state)
        {
            if (state != null)
            {
    
                if (state is List<Object>)
                {
                    // all items were saved
    
                    List<Object> allItems = (List<Object>)state;
                    saveAll = true;
                    Int32 count = lst.Count;
                    for (int i = 0; i < allItems.Count; i++)
                    {
                        if (i < count)
                            lst[i].LoadViewState(allItems[i]);
                        else
                        {
                            T item = new T();
                            item.LoadViewState(allItems[i]);
                            lst.Add(item);
                        }
                    }
                }
                else if (state is Dictionary<Int32, Object>)
                {
                    Dictionary<Int32, Object> changedItems = (Dictionary<Int32, Object>)state;
                    foreach (KeyValuePair<Int32, Object> item in changedItems)
                    {
                        if (item.Key < lst.Count)
                            lst[item.Key].LoadViewState(item.Value);
                    }
                }
            }
        }
    
        public object SaveViewState()
        {
            if (saveAll)
            {
                List<Object> allItems = new List<Object>();
                foreach (var item in lst)
                {
                    item.SetMarked();
                    allItems.Add(item.SaveViewState());
                }
                return allItems;
            }
            else
            {
                Dictionary<Int32, Object> changedItems = new Dictionary<Int32, Object>();
                for (int i = 0; i < lst.Count; i++)
                {
                    Object state = lst[i].SaveViewState();
                    if (state != null)
                    {
                        changedItems.Add(i, state);
                    }
                }
                return changedItems;
            }
        }
    
        public void TrackViewState()
        {
            isTrackingViewState = true;
            for (int i = 0; i < lst.Count; i++)
            {
                lst[i].TrackViewState();
            }
        }
    
        public int IndexOf(T item)
        {
            return lst.IndexOf(item);
        }
    
        public void Insert(int index, T item)
        {
            lst.Insert(index, item);
            if (isTrackingViewState)
                saveAll = true;
        }
    
        public void RemoveAt(int index)
        {
            lst.RemoveAt(index);
            if (isTrackingViewState)
                saveAll = true;
        }
    
        public T this[int index]
        {
            get
            {
                return lst[index];
            }
            set
            {
                lst[index] = value;
            }
        }
    
        public void Add(T item)
        {
            lst.Add(item);
            if (isTrackingViewState)
                saveAll = true;
        }
    
        public void Clear()
        {
            lst.Clear();
            if (isTrackingViewState)
                saveAll = true;
        }
    
        public bool Contains(T item)
        {
            return lst.Contains(item);
        }
    
        public void CopyTo(T[] array, int arrayIndex)
        {
            lst.CopyTo(array, arrayIndex);
        }
    
        public int Count
        {
            get { return lst.Count; }
        }
    
        public bool IsReadOnly
        {
            get { return false; }
        }
    
        public bool Remove(T item)
        {
            Boolean rslt = lst.Remove(item);
            if (isTrackingViewState)
                saveAll = true;
            return rslt;
        }
    
        public IEnumerator<T> GetEnumerator()
        {
            return lst.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public int Add(object value)
        {
            Add((T)value);
            return Count - 1;
        }
    
        public bool Contains(object value)
        {
            return Contains((T)value);
        }
    
        public int IndexOf(object value)
        {
            return IndexOf((T)value);
        }
    
        public void Insert(int index, object value)
        {
            Insert(index, (T)value);
        }
    
        public bool IsFixedSize
        {
            get { return ((IList)lst).IsFixedSize; }
        }
    
        public void Remove(object value)
        {
            Remove((T)value);
        }
    
        object IList.this[int index]
        {
            get
            {
                return lst[index];
            }
            set
            {
                lst[index] = (T)value;
            }
        }
    
        public void CopyTo(Array array, int index)
        {
            CopyTo((T[])array, index);
        }
    
        public bool IsSynchronized
        {
            get { return ((ICollection)lst).IsSynchronized; }
        }
    
        public object SyncRoot
        {
            get { return ((ICollection)lst).SyncRoot; }
        }
    }
    

    还有 StateManagedClass

    public abstract class StateManagedClass : IStateManager
    {
        private Boolean isTrackingViewState = default(Boolean);
        private StateBag viewState = default(StateBag);
    
        public StateManagedClass()
        {
            isTrackingViewState = false;
            viewState = new StateBag(false);
        }
    
        public virtual StateBag ViewState
        {
            get
            {
                return viewState;
            }
        }
    
        public bool IsTrackingViewState
        {
            get { return isTrackingViewState; }
        }
    
        public void LoadViewState(object state)
        {
            if (state != default(object))
            {
                ((IStateManager)viewState).LoadViewState(state);
            }
        }
    
        public object SaveViewState()
        {
            Object savedState = default(Object);
    
            if (viewState != null)
            {
                savedState =
                    ((IStateManager)viewState).SaveViewState();
            }
    
            return savedState;
        }
    
        public void TrackViewState()
        {
            isTrackingViewState = true;
    
            if (viewState != default(StateBag))
            {
                ((IStateManager)viewState).TrackViewState();
            }
        }
    
        public void SetMarked()
        {
            viewState.SetDirty(true);
        }
    }
    

    还有联系人类

    public class Contact : StateManagedClass 
    {
        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Name of contact"),
        NotifyParentProperty(true)
        ]
        public String Name
        {
            get
            {
                Object s = ViewState["Name"];
                return (s == null) ? String.Empty : (String)s;
            }
            set
            {
                ViewState["Name"] = value;
            }
        }
    
        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Email address of contact"),
        NotifyParentProperty(true)
        ]
        public String Email
        {
            get
            {
                Object s = ViewState["Email"];
                return (s == null) ? String.Empty : (String)s;
            }
            set
            {
                ViewState["Email"] = value;
            }
        }
    
        [
        Category("Behavior"),
        DefaultValue(""),
        Description("Phone number of contact"),
        NotifyParentProperty(true)
        ]
        public String Phone
        {
            get
            {
                Object s = ViewState["Phone"];
                return (s == null) ? String.Empty : (String)s;
            }
            set
            {
                ViewState["Phone"] = value;
            }
        }
    
    }
    

    测试控件:

    <%@ Page Title="" Language="C#" MasterPageFile="~/RTL.Master" AutoEventWireup="true" CodeBehind="WebForm15.aspx.cs" Inherits="Controls.WebForm15" %>
    
    <%@ Register Assembly="Controls" Namespace="Controls" TagPrefix="cc1" %>
    
    <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
    </asp:Content>
    <asp:Content ID="Content2" ContentPlaceHolderID="Main" runat="server">
        <cc1:QuickContacts ID="QuickContacts1" runat="server" BorderStyle="Solid" BorderWidth="1px">
            <cc1:Contact Name="someone" Email="someone@example.com"
                Phone="(555) 555-0100" />
            <cc1:Contact Name="jae" Email="jae@fourthcoffee.com"
                Phone="(555) 555-0101" />
            <cc1:Contact Name="lene" Email="lene@contoso.com"
                Phone="(555) 555-0102" />
        </cc1:QuickContacts>
        <br />
        <asp:Button runat="server" ID="Button1" Text="Add" OnClick="Button1_Click"></asp:Button>
        <asp:Button runat="server" Text="Refresh"></asp:Button>
        <br />
        <br />
        <asp:HyperLink ID="HyperLink1" NavigateUrl="~/WebForm15.aspx"
            runat="server">
        Reload Page</asp:HyperLink>
    </asp:Content>
    <asp:Content ID="Content3" ContentPlaceHolderID="script" runat="server">
    </asp:Content>
    

    还有代码隐藏:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    
    namespace Controls
    {
        public partial class WebForm15 : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
    
            }
    
            protected void Button1_Click(object sender, EventArgs e)
            {
                SkolaControlsWorkings.Controls.Contact contact = new SkolaControlsWorkings.Controls.Contact();
                contact.Name = "Name";
                contact.Email = "Email@mai.com";
                contact.Phone = "(111) 111-1111";
                QuickContacts1.Contacts.Add(contact);
                Button1.Visible = false;
            }
        }
    }
    

    现在您可以看到按下“添加”按钮如何将新的联系人项目添加到列表中,以及如何通过页面回发来维护新添加的联系人。
    这应该是一个完整的工作示例,玩得开心。
    这里是MSDN原始示例Web Control Collection Property Example

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      • 2016-12-30
      • 2012-04-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多