求解:自定义 UserControl 中包含封装了集合对象的属性被设计器自动初始化所引起的错误!

COpyFRee 2008-06-05 06:39:12

自定义 UserControl 中包含封装了 List<接口> 类型字段的属性,编译后造成引用了该 UserControl 的窗体设计器无法显示!

如题,为了便于说明问题,简化示范代码如下:

namespace TestApp
{
public interface IFace
{
void Update();
}

public partial class UserControl1 : UserControl
{
private List<IFace> face;

public List<IFace> Face
{
get
{
return face;
}
set
{
face = value;
}
}

public UserControl1()
{
InitializeComponent();

face = new List<IFace>();
}
}
}


重现过程:
---------
新建 UserControl1 和 Form1,其中 UserControl1 包含如上代码,编译生成后,将 UserControl1 从工具栏拖放到 Form1 上,保存并关闭已打开的设计器视图,再次编译,编译成功后打开窗体设计器,将会出现:类型“TestApp.IFace[]”的对象无法转换为类型“TestApp.IFace[]”的错误(如果一次没有出现,可以在 Form1 上添加一些其他控件后重复以上步骤)。

问题分析:
---------
查看 Form1.Designer.cs 文件,设计器自动在初始化的 InitializeComponent() 方法中为 userControl1.Face 属性进行了赋值,而值的内容来自于自动生成的资源文件,代码如下:

this.userControl1.Face = ((System.Collections.Generic.List<TestApp.IFace>)(resources.GetObject("userControl1.Face")));

再查看 Form1.resx,发现了 userControl1.Face 这个资源条目,而其的类型和值均为 (Nothing/null),而这就是导致窗体设计器无法显示的原因,删除这条资源和 InitializeComponent() 中 userControl1.Face 的赋值语句,窗体设计器可以正常打开了,但问题是一但修改了窗体的内容,再次编译时,Face 属性又会被重新赋值,这个资源引用也仍会被加入!
实际上,经过测试发现,自定义 UserControl 中所有封装了集合对象的属性都会被设计器自动初始化,比如:string[],只不过其不会影响设计器的行为。不知 MS 为什么要这样设计,感觉是帮了倒忙,很是让人费解。

烦请大家帮忙解决。 参与者有分!!!

...全文
227 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
COpyFRee 2008-06-06
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 gomoku 的回复:]
try putting the UserControl1 definition at the first begining:
[/Quote]

不是顺序问题,如此问题依旧!
实际上,IFace 会放在单独的 .cs 文件中,示例代码只是便于说明!
ypacyhero 2008-06-06
  • 打赏
  • 举报
回复
在拖放自定义控件时到窗体时,

实际上该自定义控件会被实例化一次。。

经常会遇到设计器无法打开,,我想也正是因为此原因。。。
ypacyhero 2008-06-06
  • 打赏
  • 举报
回复
先坐再看
烈火焚身 2008-06-06
  • 打赏
  • 举报
回复
up
gomoku 2008-06-06
  • 打赏
  • 举报
回复
try putting the UserControl1 definition at the first begining:


namespace TestApp
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();

face = new List<IFace>();
}

private List<IFace> face;

public List<IFace> Face //Move down here
{
get
{
return face;
}
set
{
face = value;
}
}

}
public interface IFace // Move down here
{
void Update();
}


}
COpyFRee 2008-06-06
  • 打赏
  • 举报
回复
刚刚提完才看到 13 楼 starts_2000 的回复,同样有效,相见恨晚啊,谢谢 starts_2000 ,谢谢大家!

结贴!!
COpyFRee 2008-06-06
  • 打赏
  • 举报
回复
哈哈,终于找到了这个 Attrib,搞定了!

[Bindable(false), Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public List<IFace> Face
{
get
{
return face;
}
set
{
face = value;
}
}
starts_2000 2008-06-06
  • 打赏
  • 举报
回复
public interface IFace
{
void Update();
}

public partial class UserControl1 : UserControl
{
private IFaceCollection _faces;

[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public IFaceCollection Faces
{
get
{
if (_faces == null)
_faces = new IFaceCollection(this);
return _faces;
}
set
{
_faces = value;
}
}

public UserControl1()
{
InitializeComponent();

Faces.Add(new Demo());
Faces.Add(new Demo());
}

public class IFaceCollection : IList, ICollection, IEnumerable
{
private UserControl1 _owner;
private List<IFace> _list;

public IFaceCollection(UserControl1 owner)
{
_owner = owner;
}

public IFace this[int index]
{
get { return List[index]; }
set { List[index] = value; }
}

public UserControl1 Owner
{
get { return _owner; }
}

public List<IFace> List
{
get
{
if (_list == null)
_list = new List<IFace>();
return _list;
}
}

public int Count
{
get { return List.Count; }
}

public void Add(IFace face)
{
if (face == null)
throw new ArgumentNullException("face");
if(!Contains(face))
List.Add(face);
}

public void AddRange(ICollection<IFace> faces)
{
if (faces == null)
throw new ArgumentNullException("faces");
foreach (IFace face in faces)
{
Add(face);
}
}

public void AddRange(IFace[] faces)
{
if (faces == null)
throw new ArgumentNullException("faces");
foreach (IFace face in faces)
{
Add(face);
}
}

public void CopyTo(IFace[] faces, int arrayIndex)
{
List.CopyTo(faces, arrayIndex);
}

public void Insert(int index, IFace face)
{
List.Insert(index, face);
}

public bool Remove(IFace face)
{
return List.Remove(face);
}

public void RemoveAt(int index)
{
List.RemoveAt(index);
}

public void Clear()
{
List.Clear();
}

public bool Contains(IFace face)
{
return List.Contains(face);
}

public int IndexOf(IFace face)
{
return List.IndexOf(face);
}

public IEnumerator GetEnumerator()
{
return List.GetEnumerator();
}

#region IList 成员

int IList.Add(object value)
{
if (!(value is IFace))
throw new ArgumentException("value");
IFace face = value as IFace;
Add(face);
return IndexOf(face);
}

void IList.Clear()
{
Clear();
}

bool IList.Contains(object value)
{
if (!(value is IFace))
throw new ArgumentException("value");
IFace face = value as IFace;
return Contains(face);
}

int IList.IndexOf(object value)
{
if (!(value is IFace))
throw new ArgumentException("value");
IFace face = value as IFace;
return IndexOf(face);
}

void IList.Insert(int index, object value)
{
if (!(value is IFace))
throw new ArgumentException("value");
IFace face = value as IFace;
Insert(index, face);
}

bool IList.IsFixedSize
{
get { return false; }
}

bool IList.IsReadOnly
{
get { return false; }
}

void IList.Remove(object value)
{
if (!(value is IFace))
throw new ArgumentException("value");
IFace face = value as IFace;
Remove(face);
}

void IList.RemoveAt(int index)
{
RemoveAt(index);
}

object IList.this[int index]
{
get
{
return this[index];
}
set
{
this[index] = value as IFace;
}
}

#endregion

#region ICollection 成员

void ICollection.CopyTo(Array array, int index)
{
CopyTo((IFace[])array, index);
}

int ICollection.Count
{
get { return Count; }
}

bool ICollection.IsSynchronized
{
get { return false; }
}

object ICollection.SyncRoot
{
get { return this; }
}

#endregion

#region IEnumerable 成员

IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}

#endregion
}
}

public class Demo : IFace
{
public Demo() { }

#region IFace 成员

public void Update()
{
throw new Exception("The method or operation is not implemented.");
}

#endregion
}
COpyFRee 2008-06-06
  • 打赏
  • 举报
回复
另,回 7 楼 jedliu ,这是标准的 WinForm C# 代码,与 SilverLight 无关。
Tll_W 2008-06-06
  • 打赏
  • 举报
回复
我也遇到过这种问题,一般我都是删掉那个初始化的一句就over了
COpyFRee 2008-06-06
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 jedliu 的回复:]
很好奇,你这里面什么都没,你想看到什么界面,这么一点代码,想出错都难啊!
还有,怎么感觉像SilverLight似的!
[/Quote]

哈哈,这位仁兄还不相信,这一点代码中以引起错误了!

另外,UserControl1 只是一个标准的继承于 UserControl 的用户控件,在 VS2005、VS2008 中新建一个用户控件时的默认生成代码就是这样啊! 当然了,因为是 partial class ,所以你可以在对应的“UserControl1.Designer.cs”中找到设计器自动生成那部分代码,我这里就没有贴上的必要了!
hiddkiller 2008-06-06
  • 打赏
  • 举报
回复
给个默认值为null行吗?
private List<IFace> face;

[System.ComponentModel.DefaultValue((List<IFace>)null)]
public List<IFace> Face //Move down here
{
get
{
return face;
}
set
{
face = value;
}
}
COpyFRee 2008-06-06
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 ydsunny 的回复:]
在UserControl的Load事件中,实现初始化即可:

C# code
public UserControl1()
{
InitializeComponent();
}

private void UserControl1_Load(object sender, EventArgs e)
{
face = new List<IFace>();
}
[/Quote]

>> private List<IFace> face;
1、face 访问修饰为 private,不允许在外部访问,Face 为对该字段的封装;
2、face 集合必须在 UserControl1 实例化时或显示前初始化,这样才能保证用户可以正常使用该控件。
jedliu 2008-06-06
  • 打赏
  • 举报
回复
很好奇,你这里面什么都没,你想看到什么界面,这么一点代码,想出错都难啊!
还有,怎么感觉像SilverLight似的!
九章落地 2008-06-06
  • 打赏
  • 举报
回复
在UserControl的Load事件中,实现初始化即可:

public UserControl1()
{
InitializeComponent();

}


private void UserControl1_Load(object sender, EventArgs e)
{
face = new List<IFace>();
}

110,529

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧