有趣。我有一个带有QuickContacts
集合的控件Contacts
。当我声明类型为Contacts
的{{1}}时,它可以正常工作,但是当使用List<Contact>
这是一个实现ContactsList<Contact>
的Generic时,它会给出“Parser Error:Type'Controls.ContactList' 1 [[Controls.Contact,Controls,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]'没有名为'Contact'的公共属性。“
在这里,此代码与IList<T>
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<Contacts>
的自定义ContactsList
。使用IList<T>, IStateManager
代替IList<T>
时,它不起作用。这是
List<T>
然后我用它如下:
public class ContactList<T> : IList<T>, IStateManager
{
“Parser Error:Type'Controls.ContactList'1 [[Controls.Contact,Controls,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null]]'没有名为'Contact'的公共属性。”
[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;
}
}
<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" />
vs List<T>
的帖子,但仍然没有回答这个问题。 IList<T>
与实现List<T>
的类之间有什么区别导致此错误?
答案 0 :(得分:0)
以下是在Microsoft http://referencesource.microsoft.com
审核List<T>
时的答案
[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);
}
}
和Contact类
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