自定义组件在设计器中工作,但在代码中不可见

问题描述 投票:0回答:1

我创建了一个自定义组件,派生自

BindingSource
并且它似乎按预期工作。
当我将它放在窗体上时,我可以设置所有属性,其他控件可以看到它并可以将它用作数据源进行绑定。这一切都很好。

我的问题是,当我想在代码中访问这个组件时,代码编辑器一直告诉我没有这个组件。
这怎么可能?

它在设计器中显示,我可以设置属性,我可以让它与设计器中的其他控件交互,并且在运行时它完美运行。
但是代码编辑器找不到,一直说:

名称 gttDatasource1" 在当前上下文中不存在

什么会导致这个?如何解决?

我尝试清理/重建
我尝试重启 VS
我试过重启电脑

编辑
表格的

Designer.cs
部分我把组件放到了:

namespace Test_app
{
    partial class FormLogSCSSalesInvoiceList
    {
        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormLogSCSSalesInvoiceList));
            gttControls.gttDataSource gttDataSource1 = new gttControls.gttDataSource();

自定义组件在

Designer.cs

自定义组件的部分代码

namespace gttControls
{
    internal class gttDataSourceCodeDomSerializer : CodeDomSerializer
    {
        public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
        {
            CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.GetSerializer(typeof(gttDataSource).BaseType, typeof(CodeDomSerializer));
            var Result = baseClassSerializer.Deserialize(manager, codeObject);
            ((gttDataSource)Result).CorrectTableColumns();
            return Result;
        }
    }

    public delegate void OnActiveChangedHandler(object sender, EventArgs e);
    public delegate void OnBeforeUpdateHandler(object sender, EventArgs e);

    [DesignerSerializer(typeof(gttDataSourceCodeDomSerializer), typeof(CodeDomSerializer))]
    public partial class gttDataSource : BindingSource
    {
        private readonly gttDataTable _gttDataTable;
        private GttTableProperties _gttTableProperties;
        private Collection<gttDataTableColumn> _columns = new Collection<gttDataTableColumn>();
        private bool _active = false;
        private readonly bool _refreshSchema = false;

        public event ActiveChangedHandler ActiveChanged;
        public event BeforeUpdateHandler BeforeUpdate;

        public gttDataSource()
        {
            _gttTableProperties = new GttTableProperties(this);
            _gttDataTable = new gttDataTable();
            DataSource = _gttDataTable.Table;
            _gttDataTable.BeforeUpdate += _gttDataTable_BeforeUpdate;
        }
    }
}

编辑2
当我尝试在代码中使用这个组件时,我得到了这个:

并证明组件实际上在表单的设计器中:

编辑 3
我按照评论中的建议添加了一个演员:

public gttDataSource(IContainer container) : this() 
{ 
    if (container == null) 
    { 
        throw new ArgumentNullException("container is null"); 
    } 
    container.Add(this);
}

但这并没有帮助。将组件拖放到窗体上时或任何其他时间都不会调用此构造函数。

c# .net winforms custom-component codedom
1个回答
2
投票

症状
实现自定义 CodeDomSerializer 的自定义组件,当添加到表单容器时,生成一个无法从包含它的表单类访问的对象,should 定义和生成组件的实例(作为

private
字段) .

问题与自定义

CodeDomSerializer
实现有关。
实现基本
CodeDomSerializer
的自定义序列化程序必须覆盖
Deserialize()
Serialize()
方法。
从文档的备注部分(注意must,而不是should):

要为类型实现自定义 CodeDomSerializer,您必须:

  • 定义一个派生自 CodeDomSerializer 的类。

  • 为序列化或反序列化方法实现方法覆盖。

  • 使用 DesignerSerializerAttribute 将您的自定义 CodeDomSerializer 实现与一种组件相关联。

要让默认序列化程序生成以标准方式配置组件/控件的代码语句,我们必须为组件调用基本序列化程序。
否则,序列化器不会执行完整的序列化,只是使用它可以访问的类型创建一个本地对象。
因此,它不会创建关联的字段,并且在设计器中分配的属性值的序列化也不会遵循标准的logic(该对象的属性可能分散在

Designer.cs
文件中)。

在问题中,不清楚此处发布的代码是否是完整的

CodeDomSerializer
实现。
要按预期工作,自定义
CodeDomSerializer
必须包括
Serialize()
方法覆盖并指定应序列化的类型。
然后调用基类的默认
Serialize()
方法,生成Componenent的标准序列化,现在分配给实例Field,然后可以在Container Form类中访问:

internal class gttDataSourceCodeDomSerializer : CodeDomSerializer
{
    public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
    {
        CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.GetSerializer(typeof(gttDataSource).BaseType, typeof(CodeDomSerializer));
        var Result = baseClassSerializer.Deserialize(manager, codeObject);
        ((gttDataSource)Result).CorrectTableColumns();
        return Result;
    }

    public override object Serialize(IDesignerSerializationManager manager, object value)
    {
        var serializer = (CodeDomSerializer)manager.GetSerializer(typeof(gttDataSource).BaseType, typeof(CodeDomSerializer));
        return serializer.Serialize(manager, value);
    }
}

组件提供接受 IContainer 对象的构造函数也很重要。这用于正确处理组件,因为窗体基类的默认

Dispose()
方法
Control
)只考虑子控件,而不是组件。
CodeDomSerialzier
考虑这个构造函数并添加
Designer.cs
:

this.gttDataSource1 = new gttControls.gttDataSource(this.components);
// [...]
private gttControls.gttDataSource gttDataSource1;

如果之前没有添加其他组件,它还会创建:

 this.components = new System.ComponentModel.Container();

所以 Form 类的

Dispose()
覆盖处理了这个:

protected override void Dispose(bool disposing)
{
    if (disposing && (components != null))
    {
        components.Dispose();
    }
    base.Dispose(disposing);
}

简单的实现:

public partial class gttDataSource : BindingSource
{
    public gttDataSource() => InitializeComponent();

    public gttDataSource(IContainer container) : this()
    {
        if (container is null) { 
            throw new ArgumentNullException("container is null"); 
        }
        container.Add(this);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.