UserControl 集合未标记为可序列化

Posted

技术标签:

【中文标题】UserControl 集合未标记为可序列化【英文标题】:UserControl collection not marked as serializable 【发布时间】:2012-04-05 01:17:24 【问题描述】:

我一定遗漏了一些非常明显的东西。我对 C# 很陌生,但多年来一直在 C/C++ 中编程,如果它是显而易见的东西,我很抱歉;)

[查看编辑以了解较新的问题]

我正在尝试创建一个包含 UserControl 的节点。我有控件出现在 WinForm 设计器中,我可以向它添加节点。但是,当我尝试运行代码时,出现以下错误:

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

然后我添加的节点都没有显示出来。

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

节点定义如下:

[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; 
;

然后我定义一个“集合”如下:

[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 的 cmets,这是我的 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”属性相关的帖子以来,我已经进行了一些修改,这有帮助,但我现在收到以下构建错误:

错误 MSB3103:Resx 文件无效。无法加载类型 App.Node、App、 Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 用于 .RESX 文件。确保已添加必要的引用 到你的项目。

编辑 2:值得注意的是,我的问题仅在我在设计器中添加一堆节点时才会出现,然后出现上述 Resx 错误。如果我从代码中手动添加节点,那么一切都会按我的预期工作......

【问题讨论】:

你使用什么控件?是定制的吗? @Archeg:是的,它完全自定义直接从 UserControl 派生 您可以发布您的 UserControl 代码吗? @Archeg:添加了代码并根据我的最新问题稍微更新了... 【参考方案1】:

我相信您遇到了这个问题,因为 Designer 会自动尝试序列化所有公共 UserControl 属性。如果您的自定义 UserControl 设计时支持不需要此属性,则可以添加“DesignerSerializationVisibility”属性:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 

或者干脆省略属性的getset 方法,将其用作公共字段。

希望对你有帮助!

【讨论】:

【参考方案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);

【讨论】:

添加了另一个解决问题的方法 在底部添加了额外的编辑。基本上问题在于设计师出了问题......不知道这是否对你有帮助 是的,似乎 VS 无法在它正在构建的控件上生成序列化数据。你介意我把它作为一个错误发布给微软,因为我无法找到一些有意义的解释吗? 不知道我怎么没发现那个更新......但是是的,我真的希望能够使用设计师...... 如果你认为它会有所作为,那就去吧(IME,你需要亲自让一名 MS 员工下来,以便从错误报告中获得任何用途;))【参考方案3】:

我解决了这个问题,确保属性类有一个无参数的构造函数。 在将类序列化为类没有无参数构造函数的文件时,我遇到了类似的问题。

    [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;
        
    

【讨论】:

以上是关于UserControl 集合未标记为可序列化的主要内容,如果未能解决你的问题,请参考以下文章

错误 - 未标记为可序列化

创建 WCF 代理时数据协定未标记为可序列化

AppDomain CreateInstanceAndUnwrap:类型未标记为可序列化

类型“System.Web.HttpInputStream”未标记为可序列化

创建与插件一起使用的应用程序域:“程序集中的类型未标记为可序列化

如何识别c__DisplayClass未标记为可序列化的位置