【问题标题】:C# Winforms Visual Studio designer cannot find custom typeC# Winforms Visual Studio 设计器找不到自定义类型
【发布时间】:2011-01-13 08:48:19
【问题描述】:

我有一个带有自定义类型通用列表的自定义控件。此列表定义为公开:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Editor(typeof(ButtonPanelXEditor), typeof(UITypeEditor))]
public List<CompactButton> CompactButtons
{
    get { return _compactButtons; }
    set { _compactButtons = value; }
}

当我将此控件添加到我的表单并构建我的项目时,我收到此错误:

错误 1 ​​找不到名称的类型。类型名称为 'ButtonPanelX.CompactButton, ButtonPanelX, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'。第 127 行,位置 5。D:\Projecten\ButtonPanelX\ButtonPanelX\Form1.resx 127 5 ButtonPanelX

当我使用字符串而不是自定义对象时,设计器会保存我的列表。 CompactButton 具有属性[Serializable] 并派生自ISerializable

我能做些什么来解决这个问题?

编辑:

public class ButtonPanelXEditor : UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
    {
        if (context != null && context.Instance != null)
            // We will use a window for property editing. 
            return UITypeEditorEditStyle.Modal;

        return base.GetEditStyle(context);
    }

    public override object EditValue(System.ComponentModel.ITypeDescriptorContext context,
        IServiceProvider provider, object value)
    {

        context.OnComponentChanging();

        ButtonPanel b = context.Instance as ButtonPanel;

        FooBar form = new FooBar();
        form.Buttons = b.CompactButtons;

        form.ShowDialog();

        b.CompactButtons = form.Buttons;

        b.DrawButtons();

        context.OnComponentChanged();

        return form.Buttons;
    }
}

编辑 2:

[Serializable]
public partial class ButtonPanel : UserControl
{
    private ArrayList _compactButtons;

    public ButtonPanel()
    {
        InitializeComponent();

        _compactButtons = new ArrayList();

        AddButtons();

        this.Load += new EventHandler(ButtonPanel_Load);

    }

    void ButtonPanel_Load(object sender, EventArgs e)
    {
        DrawButtons();
    }


    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Editor(typeof(ButtonPanelXEditor), typeof(UITypeEditor))]
    public ArrayList CompactButtons
    {
        get { return _compactButtons; }
    }

    public void DrawButtons()
    {
        baseButton1.Visible = ((CompactButton)_compactButtons[0]).Visible;
        baseButton2.Visible = ((CompactButton)_compactButtons[1]).Visible;
    }

    private void AddButtons()
    {
        /* Buttons baseButton1 and baseButton2 are created by the designer */

        CompactButton c = new CompactButton();
        c.Enabled = baseButton1.Enabled;
        c.Visible = baseButton1.Visible;
        c.Name = baseButton1.Name;

        CompactButton c2 = new CompactButton();
        c2.Enabled = baseButton2.Enabled;
        c2.Visible = baseButton2.Visible;
        c2.Name = baseButton2.Name;

        _compactButtons.Add(c);
        _compactButtons.Add(c2);
    }
}

【问题讨论】:

  • 你的类型是 CompactButton 还是 CompactButtons?在您的代码 sn-p 中,您将其称为 CompactButton,而在问题文本中您说 CompactButtons。
  • 我的类型名为CompactButton。我已经编辑了我的问题。
  • 您项目的目标框架版本是什么?谷歌表示如果目标是 3.5 框架会有一些问题。
  • 我也发现了,但是将其更改为版本 4 并不能解决我的问题。
  • 为什么要将按钮序列化到资源文件而不是后面的代码?

标签: c# visual-studio winforms visual-studio-2010


【解决方案1】:

您可以尝试将它们序列化为后面的代码,而不是将您的按钮序列化到资源文件中。为此,您需要为您的CompactButton 类型实现自定义TypeDescriptor,并在那里处理转换为InstanceDescriptor。看How to Implement a TypeConverter。示例:

[TypeConverter(typeof(CompactButtonTypeConverter))]
public class CompactButton: ... {
  ...
}

public class CompactButtonTypeConverter: TypeConverter {

  public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
    if (destinationType == typeof(InstanceDescriptor)) 
       return true;
    return base.CanConvertTo(context, destinationType);
  }

  public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
    if (destinationType == typeof(InstanceDescriptor) && value is CompactButton) {
      // This assumes you have a public default constructor on your type.
      ConstructorInfo ctor = typeof(CompactButton).GetConstructor();
      if (ctor != null) 
         return new InstanceDescriptor(ctor, new object[0], false);
    }
    return base.ConvertTo(context, culture, value, destinationType);      
  }

}

有关详细信息,另请参阅InstanceDescriptor 类。

更新:至于您的UITypeEditor 和CompactButtons 属性,您不需要setter。如下更改您的 CompactButtons 属性:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content), Editor(typeof(ButtonPanelXEditor), typeof(UITypeEditor))]
public List<CompactButton> CompactButtons
{
    get { return _compactButtons; } // _compactButtons must of course be initialized.
}

然后你可以像这样实现UITypeEditor的EditValue方法:

public override object EditValue(System.ComponentModel.ITypeDescriptorContext context,
  IServiceProvider provider, object value) {
  if (context == null || provider == null)
    return null;

  var b = context.Instance as ButtonPanel;
  if (b == null)
    return value;

  var editorService = (IWindowsFormsEditorService)
    provider.GetService(typeof(IWindowsFormsEditorService));
  if (editorService == null)
    return null;

  // This constructor should copy the buttons in its own list.
  using (var form = new FooBar(b.CompactButtons)) {
    if (editorService.ShowDialog(form) == DialogResult.OK && context.OnComponentChanging()) {
      b.CompactButtons.Clear();
      b.CompactButtons.AddRange(form.Buttons);
      context.OnComponentChanged();
    }
  }
  return value;
}

如果您的编辑器表单不是很专业,您可以试试CollectionEditor

【讨论】:

  • 序列化到后面的代码是什么意思?我怎样才能做到这一点?你能发布一些示例代码吗?
  • 感谢您提供示例。但我仍然不明白如何使用它。序列化发生在哪里?我需要在哪里这样做?如何打开后面的代码?对不起,对我来说这听起来像中文。 (我来自荷兰:))
  • winforms 的代码位于 .Designer 文件中,在您的情况下,您应该有一个 Form1.Designer.cs。其中有一个部分类定义,其中包含 InitializeComponent 方法,并且如果正在序列化的类型不支持 CodeDom 序列化,则您在表单设计器上更改的所有内容都将序列化为该方法或资源文件的代码。
  • 好的,在我的例子中,Visual Studio 将值存储在 resx 文件中。你的建议是不要这样做,对吧?您建议在部分设计器类中执行此操作。但我仍然不明白我怎么能做到这一点。在我的代码中的某个地方,我必须打开 Designer.cs 并插入一些 C# 代码?怎么样?
  • InitializeComponent 方法中的代码是通过 CodeDom 序列化生成的。要提供 CodeDom 序列化功能,您的类型必须与支持转换为 InstanceDescriptor 对象的 TypeConverter 相关联,或者提供自定义 CodeDomSerializer。在大多数情况下,TypeConverter 就足够了。如果您像我的示例中那样为您的CompactButton 实现TypeConverter,那就足够了。 Winforms 设计器将能够将您的CompactButton 转换为InstanceDescriptor,然后可以将其序列化为 InitializeComponent。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 2012-03-21
  • 1970-01-01
  • 2012-09-06
相关资源
最近更新 更多