自定义组件在设计器中工作,但在代码中不可见
Custom component works in the Designer, but is invisible in code
我创建了一个自定义组件,派生自 BindingSource
,它似乎按预期工作。
当我将它放在窗体上时,我可以设置所有属性,其他控件可以看到它并可以将它用作数据源进行绑定。这一切都很好。
我的问题是,当我想在代码中访问这个组件时,代码编辑器一直告诉我没有这个组件。
这怎么可能?
它显示在设计器中,我可以设置属性,我可以让它与设计器中的其他控件交互,并且在运行时它完美地工作。
但是代码编辑器找不到,一直说:
The name gttDatasource1" does not exists in the current context
这是什么原因造成的?如何解决?
我试过了clean/rebuild
我尝试重启 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
我按照评论中的建议添加了一个 ctor:
public gttDataSource(IContainer container) : this()
{
if (container == null)
{
throw new ArgumentNullException("container is null");
}
container.Add(this);
}
但这并没有帮助。将组件拖放到窗体上时或任何其他时间都不会调用此构造函数。
症状:
实现自定义 CodeDomSerializer 的自定义组件在添加到表单容器时会生成一个无法从包含它的表单 class 访问的对象,并且 应该 定义并生成组件的实例(作为 private
字段)。
此问题与自定义 CodeDomSerializer
实施有关。
实现基本 CodeDomSerializer
的自定义序列化程序必须覆盖 Deserialize()
和 Serialize()
方法。
来自文档的备注部分(注意必须,而不是应该):
To implement a custom CodeDomSerializer for a type, you must:
Define a class that derives from CodeDomSerializer.
Implement method overrides for serialization or deserialization methods.
Associate your custom CodeDomSerializer implementation with a type of component using a DesignerSerializerAttribute.
为了让默认序列化程序生成以标准方式配置组件/控件的代码语句,我们必须为组件调用基本序列化程序。
否则,序列化程序不会执行完整的序列化,只会使用它可以访问的类型创建一个本地对象。
因此,它不会创建关联的字段,并且在设计器中分配的 属性 值的序列化也不会遵循标准 逻辑 (此对象的属性可能分散在 Designer.cs
文件中)。
问题中不清楚此处发布的代码是完整的 CodeDomSerializer
实现。
要按预期工作,自定义 CodeDomSerializer
必须包含 Serialize()
方法覆盖并指定应序列化的类型。
然后调用基础 class 的默认 Serialize()
方法,生成组件的标准序列化,现在分配给实例 Field,然后可以在容器表单中访问 class:
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);
}
}
同样重要的是,组件提供一个接受表单基础 class 的 IContainer object. This is used to properly dispose of Components, since the default Dispose()
method 的构造函数 class (Control
) 只考虑子控件,而不考虑组件。
CodeDomSerialzier
考虑此构造函数并添加 Designer.cs
:
this.gttDataSource1 = new gttControls.gttDataSource(this.components);
// [...]
private gttControls.gttDataSource gttDataSource1;
如果之前没有添加其他组件,它还会创建:
this.components = new System.ComponentModel.Container();
所以 Dispose()
覆盖表单 class 会处理这个问题:
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 == null) {
throw new ArgumentNullException("container is null");
}
container.Add(this);
}
}
我创建了一个自定义组件,派生自 BindingSource
,它似乎按预期工作。
当我将它放在窗体上时,我可以设置所有属性,其他控件可以看到它并可以将它用作数据源进行绑定。这一切都很好。
我的问题是,当我想在代码中访问这个组件时,代码编辑器一直告诉我没有这个组件。
这怎么可能?
它显示在设计器中,我可以设置属性,我可以让它与设计器中的其他控件交互,并且在运行时它完美地工作。
但是代码编辑器找不到,一直说:
The name gttDatasource1" does not exists in the current context
这是什么原因造成的?如何解决?
我试过了clean/rebuild
我尝试重启 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
我按照评论中的建议添加了一个 ctor:
public gttDataSource(IContainer container) : this()
{
if (container == null)
{
throw new ArgumentNullException("container is null");
}
container.Add(this);
}
但这并没有帮助。将组件拖放到窗体上时或任何其他时间都不会调用此构造函数。
症状:
实现自定义 CodeDomSerializer 的自定义组件在添加到表单容器时会生成一个无法从包含它的表单 class 访问的对象,并且 应该 定义并生成组件的实例(作为 private
字段)。
此问题与自定义 CodeDomSerializer
实施有关。
实现基本 CodeDomSerializer
的自定义序列化程序必须覆盖 Deserialize()
和 Serialize()
方法。
来自文档的备注部分(注意必须,而不是应该):
To implement a custom CodeDomSerializer for a type, you must:
Define a class that derives from CodeDomSerializer.
Implement method overrides for serialization or deserialization methods.
Associate your custom CodeDomSerializer implementation with a type of component using a DesignerSerializerAttribute.
为了让默认序列化程序生成以标准方式配置组件/控件的代码语句,我们必须为组件调用基本序列化程序。
否则,序列化程序不会执行完整的序列化,只会使用它可以访问的类型创建一个本地对象。
因此,它不会创建关联的字段,并且在设计器中分配的 属性 值的序列化也不会遵循标准 逻辑 (此对象的属性可能分散在 Designer.cs
文件中)。
问题中不清楚此处发布的代码是完整的 CodeDomSerializer
实现。
要按预期工作,自定义 CodeDomSerializer
必须包含 Serialize()
方法覆盖并指定应序列化的类型。
然后调用基础 class 的默认 Serialize()
方法,生成组件的标准序列化,现在分配给实例 Field,然后可以在容器表单中访问 class:
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);
}
}
同样重要的是,组件提供一个接受表单基础 class 的 IContainer object. This is used to properly dispose of Components, since the default Dispose()
method 的构造函数 class (Control
) 只考虑子控件,而不考虑组件。
CodeDomSerialzier
考虑此构造函数并添加 Designer.cs
:
this.gttDataSource1 = new gttControls.gttDataSource(this.components);
// [...]
private gttControls.gttDataSource gttDataSource1;
如果之前没有添加其他组件,它还会创建:
this.components = new System.ComponentModel.Container();
所以 Dispose()
覆盖表单 class 会处理这个问题:
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 == null) {
throw new ArgumentNullException("container is null");
}
container.Add(this);
}
}