用户控件集合未标记为可序列化。

11

我一定是漏掉了某些非常显然的东西。我对C#相当新,但已经在C/C++中进行编程多年了,如果确实有什么非常明显的问题,请原谅 ;)

[请查看编辑以获取更新的问题]

我正在尝试创建包含UserControl的节点。我在WinForm设计器中看到控件出现,并且我可以向其中添加节点。但是当我尝试运行代码时,我会遇到以下错误:

  

属性'Nodes'的代码生成失败。 错误是:程序集“App,version=1.0.0.0,Culture=neutral,PublicKeyToken=null”中的类型    App.Node未标记为可序列化。

然后我添加的所有节点都不会显示。

就我所知,它已标记为可序列化,这让我开始发疯了。

该节点定义如下:

[Serializable]
public class Node : MarshalByRefObject
{
    public Node()
    {
    }

    public Node( String text )
    {
        this.Text       = text;
        this.Checked    = false;
        this.Complete   = false;
    }

    public String       Text        { get; set; }
    public bool         Checked     { get; set; }
    public bool         Complete    { get; set; }
    public bool         Selected    { get; set; }
};

我接下来定义一个“Collection”:

[Serializable]
public class NodeCollection : List< Node >
{
    public NodeCollection() :
        base()
    {
    }
};

你可以看到,这个集合和节点本身都设置了"Serializable"属性。

在错误中提到的Nodes属性定义如下:

    private NodeCollection      mNodes  = new NodeCollection();

    [Category( "Behavior" )]
    [Description( "Nodes" )]
    public NodeCollection Nodes
    { 
        get
        {
            return mNodes;
        }
    }

有人知道我在这里做错了什么吗?

编辑: 根据 Archeg 的评论,这是我的 UserControl:

public partial class Control : UserControl
{
    public Control()
    {
        InitializeComponent();
    }

    protected override void OnPaint( PaintEventArgs pe )
    {
        Graphics graph  = pe.Graphics;

        int rowHeight   = Font.Height + 2;

        if ( Nodes != null )
        {
            int yPos    = 0;
            foreach( Node node in this.Nodes )
            {
                // Calculate my various bounding boxes.
                Rectangle nodeBounds    = new Rectangle( Bounds.Left, yPos, Bounds.Width, rowHeight );
                Rectangle lightBounds   = new Rectangle( Bounds.Right - Font.Height, yPos, rowHeight, rowHeight );
                Rectangle spannerBounds = new Rectangle( lightBounds.Left - Font.Height, yPos, rowHeight, rowHeight );
                Rectangle checkBoxBound = new Rectangle( 32, yPos, rowHeight, rowHeight );
                Rectangle textBounds    = new Rectangle( checkBoxBound.Right, yPos, Bounds.Width - (rowHeight * 2) - checkBoxBound.Right, rowHeight );

                // Draw selection box.
                Brush textColour    = Brushes.Black;
                if ( node.Selected )
                {
                    graph.FillRectangle( Brushes.Blue, nodeBounds );
                    textColour      = Brushes.Yellow;
                }

                // Draw node text.
                graph.DrawString( node.Text, Font, textColour, textBounds );

                // Draw Red/Green light
                Image[] lightImages = new Image[] { CompleteLightImage, InCompleteLightImage };
                Image lightImage    = lightImages[node.Complete ? 1 : 0];
                if ( lightImage != null )
                {
                    graph.DrawImage( lightImage, lightBounds );
                }

                // Draw Spanner Icon
                if ( SettingsImage != null )
                {
                    graph.DrawImage( SettingsImage, spannerBounds );
                }
                // Draw check box.
                VisualStyleRenderer renderer    = null;
                VisualStyleElement  ve          = node.Checked ? VisualStyleElement.Button.CheckBox.CheckedPressed : VisualStyleElement.Button.CheckBox.CheckedNormal;
                if (VisualStyleRenderer.IsElementDefined( ve ))
                {
                    renderer = new VisualStyleRenderer( ve );
                }

                if ( renderer != null )
                {
                    renderer.DrawBackground( graph, checkBoxBound );
                }
                else
                {
                    ControlPaint.DrawCheckBox( graph, checkBoxBound, node.Checked ? ButtonState.Checked : ButtonState.Normal );
                }
                yPos    += Font.Height;
            }
        }
    }

    private NodeCollection      mNodes  = new NodeCollection();

    [Category( "Behavior" )]
    [Description( "Nodes" )]
    [DesignerSerializationVisibility( DesignerSerializationVisibility.Content )]
    [MergableProperty( false )]
    [Bindable( false )]
    public NodeCollection Nodes
    { 
        get
        {
            return mNodes;
        }
    }

    public Image CompleteLightImage         { get; set; }
    public Image InCompleteLightImage       { get; set; }
    public Image SettingsImage              { get; set; }
}

我发布后进行了一些修改,主要涉及“DesignerSerializationVisibility”属性,这有所帮助,但现在出现以下构建错误:

error MSB3103: 无效的 Resx 文件。无法加载在 .RESX 文件中使用的类型 App.Node,App,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null。请确保已向项目添加必要的引用。

编辑2:值得注意的是,只有在我从设计器中添加一堆节点时才会出现上述Resx错误。如果我手动从代码中添加节点,则一切都按照我的期望工作...


你使用哪个控件?是自定义的吗? - Archeg
@Archeg:是的,它完全是直接从UserControl自定义派生的。 - Goz
你能发布你的用户控件代码吗? - Archeg
@Archeg:添加了代码并稍微更新了一下,附上我的最新问题... - Goz
3个回答

28

我认为您遇到这个问题是因为Designer自动尝试序列化所有公共的UserControl属性。如果此属性在您的自定义UserControl设计时不需要,那么您可以添加“DesignerSerializationVisibility”属性:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 

或者直接忽略属性中的 get{}set{} 方法,将其作为公共字段使用。

希望能对你有所帮助!


2

这很奇怪。我在我的笔记本上复制了它,然后将Node类移动到另一个项目中,它就可以工作了。我认为这与循环依赖有关——它试图找到你的程序集(在我的情况下是WindowsFormsApplication1),但由于正在构建它,因此无法找到。

希望这对你有所帮助,我会继续深入挖掘。

更新 解决方法之一:从Node类中删除[Serialization]属性。在这种情况下,您将强制VS而不是在resx文件中生成Node内容,只生成这样的代码:

// Form1.designer.cs:
Node node1 = new Node(); 
node1.Checked = false;
node1.Complete = false;
node1.Selected = false;
node1.Text = null;
this.contr1.Nodes.Add(node1);

添加了另一种解决方案来解决这个问题。 - Archeg
在底部添加了额外的编辑。基本上问题出在设计师出了一些问题...不知道这是否对您有所帮助。 - Goz
是的,似乎VS无法在它正在构建的控件上生成序列化数据。如果我把这个问题作为一个漏洞提交给微软,你介意吗?因为我没有找到任何有意义的解释。 - Archeg
不知道我怎么没注意到那个更新...但是我真的想能够使用设计师... - Goz
1
如果你认为这会有任何不同,就去做吧(在我看来,你需要亲自抓住微软的员工才能从错误报告中获得任何帮助;) - Goz

0

我解决了这个问题,确保属性类具有无参数的构造函数。 当将类序列化到文件时,如果类没有无参数的构造函数,我曾经遇到过类似的问题。

    [Serializable]
    public class ChartTitle {
        public Color BackColor { get; set; }
        public string Text { get; set; }

        public ChartTitle() {   // <--- Make sure have parameterless constructor
            BackColor = SystemColors.Control;
            Text = String.Empty;
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接