如何使用“自定义UITypeEditor C#WindowsFormApplication"在“设计时"中保存收集数据? [英] How to save collection data in Design Time with Custom UITypeEditor C# WindowsFormApplication?

查看:130
本文介绍了如何使用“自定义UITypeEditor C#WindowsFormApplication"在“设计时"中保存收集数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了自己的UITypeEditor,并在@Sefe和

I wrote my own UITypeEditor and I reached my goal with help of @Sefe and with THIS link.

我的基本设置:

在此设置中,BaseForm扩展了System.Windows.Forms.Form.在这里,我将放置具有自定义UITypeEditor(如模式样式)的属性(List<Control> ActionButtons).

In this setup, BaseForm extends System.Windows.Forms.Form. Here i'm putting my property (List<Control> ActionButtons) that have a custom UITypeEditor like a modal style.

恢复的工作流程(所有这些都在设计时):

   1-打开MyForm.
    2-单击MyForm属性面板上的ActionButtons(由BaseForm继承)省略号.     3-打开一个自定义表单,其中包含我要选择的膨胀对象. (此表格由我的CustomUITypeEditor调用)
    4-拾取所需的对象,然后关闭表单.因此,现在MyForm中的数据正常,并将其序列化到Designer.cs文件中.我可以重新打开该EditorUI,再次在省略号中单击,然后查看我之前选择的对象.
    5-现在,当我关闭MyForm并重新打开它时,所有数据都会丢失!!!但是数据仍然序列化到Designer.cs中.     6-如果我使用string而不是List<Control>完成所有这些步骤,则一切正常.

    1 - Open MyForm.
    2 - Click at ActionButtons(inherited by BaseForm) ellipsis [...] on MyForm properties panel.
    3 - A custom form is opened with inflated objects that I want pick. (this form is called by my CustomUITypeEditor)
    4 - Objects that I want are picked, and I close the form. So now, the data are ok in MyForm and serialized into Designer.cs file. I can reopen that EditorUI clicking again in ellipsis and see objects that I picked before.
    5 - Now when I close MyForm and reopen it, all data are lost!!! But the data still serialized into Designer.cs.     6 - If I do all this steps with a string instead List<Control>, all are Ok.

在我的代码下面:

public class CollectionTypeEditor : UITypeEditor {

private IWindowsFormsEditorService _editorService = null;
private ICollection<Control> mControls = null;
private List<Control> mPickedControls = null;

// Editor like Modal style
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) {
  return UITypeEditorEditStyle.Modal;
}

// Opens modal and get returned data
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) {
  if (provider == null)
    return value;

  _editorService = (IWindowsFormsEditorService) provider
    .GetService(typeof(IWindowsFormsEditorService));

  if (_editorService == null)
    return value;

  mControls = new List<Control>();

  // retrieve old data
  mPickedControls = value as List<Control>;
  if (mPickedControls == null)
    mPickedControls = new List<Control>();

  // getting existent controls that will be inflated in modal
  Control mContext = (Control) context.Instance;
  GetControls(mContext);

  // open form and get response
  CollectionDesign<Control> frmCollections = new CollectionDesign<Control>(mControls, ref mPickedControls);
  var response = _editorService.ShowDialog(frmCollections);

  // returning data from editor
  return response == DialogResult.OK ? mPickedControls : value;
}

这里一切都很好. BaseForm中我的变量的代码.附言:此变量将显示在MyForm上,我在其中单击省略号[...]

Everything works well here. Code for my variable in BaseForm. Ps.: this variable will be showed on MyForm where I make click at ellipsis [...]

[Editor(typeof(CollectionTypeEditor), typeof(UITypeEditor))]
[TypeConverter(typeof(ActionButtonConverter))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Control> ActionButtons { get; set; }

添加了序列化属性,因为无法保存文件.关闭并重新打开窗体时,所有数据都将丢失.

The serialization attribute was added because the file couldn't be saved. When form is closed and reopened, all data are lost.

奇怪的是,我编写了其他UITypeEditor,例如相同的方式,只是将数据类型更改为string,我可以关闭或重新打开表单,并且一切正常,数据已保存

The stranger thing is that I wrote other UITypeEditor like the same way, just changing type of data to string and I can close or reopen my form and all works fine, the data are saved.

我已经添加了TypeConverter,但我认为这里不是这样.我的代码有什么问题?

I already added a TypeConverter but I think that isn't case here. what is wrong with my code?

我在重新打开表单时遇到此错误:

I'm getting this error on reopen form:

Severity Code Description Project File Line Suppression State Message Method 'System.CodeDom.CodePropertyReferenceExpression.Add' not found.        


更新

现在,当我关闭或重新打开控件时,我的控件列表存储在myForm.designer文件中,但是控件未附加在属性网格上.即:如果在关闭时单击省略号以添加按钮'addbt'并重新打开myForm,则会自动生成代码.


UPDATE

Now my List of controls are stored in myForm.designer file when it's closed or reopened, but the controls don't are attached on property grid. i.e.: If I click on ellipsis to add a Button 'addbt' when close and reopen myForm the code is auto generated.

代码自动在myForm.designer上生成:

Code auto generated bellow on myForm.designer:

  // 
  // addbt
  // 
  this.addbt.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
  this.addbt.Cursor = System.Windows.Forms.Cursors.Hand;
  this.addbt.Font = new System.Drawing.Font("Tahoma", 9F);
  this.addbt.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(222)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))));
  this.addbt.Location = new System.Drawing.Point(13, 6);
  this.addbt.Name = "addbt";
  this.addbt.Size = new System.Drawing.Size(103, 33);
  this.addbt.TabIndex = 0;
  this.addbt.Text = "Incluir";
  this.addbt.UseVisualStyleBackColor = true;

  // 
  // myForm
  // 
  this.ActionButtons.Add(this.addbt);

如果再次单击省略号,则数据将附加到myForm的PropertyGrid上的属性.但是,当我重新打开myForm时,之前存储的值不会传递到myForm的PropertyGrid上的属性(数据仍存储在自动生成的代码设计器中).因此,当单击省略号时,EditValue方法中的value不会附带存储的数据.我觉得离它更近了:)

If I make a click on ellipsis again, the data are attached to property on myForm's PropertyGrid. But when I reopen myForm, this values stored before aren't passed to property on myForm's PropertyGrid (data still stored in auto generated code designer). So when a click on the ellipsis [...] the value from EditValue method not comes with data stored. I'm feeling that it's closer :)

下面的TypeConverter可能有问题:

Maybe something is wrong with my TypeConverter below:

public class ActionButtonConverter : TypeConverter {

public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
  if (sourceType == (typeof(string)))
    return true;

  return base.CanConvertFrom(context, sourceType);
}

public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
  if(value.GetType() == typeof(string)) {
    List<Control> ctrs = value as List<Control>;

    if (ctrs != null)
      return ctrs;
  }

  return base.ConvertFrom(context, culture, value);
}


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

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
  if (value == null)
    return "null";

  if (destinationType == typeof(string))
    return "(custom collection)";

  return base.ConvertTo(context, culture, value, destinationType);
}

我认为反序列化有任何错误.重新打开myForm时,ITypeDescriptorContext或值(TypeConverter)没有任何有关将数据序列化到designer.cs文件中的信息.

I think that I have anything error in deserialization. When myForm is reopened the ITypeDescriptorContext or value (TypeConverter) don't have anything about serialized data into designer.cs file.

谢谢,抱歉,我的语言不好:P

Thanks all, and sorry for bad language :P

推荐答案

几天后,我找到了解决此问题的方法.我解决了这个问题,创建了自己的Button集合,该按钮继承了CollectionBase:

After some days I found the solution for this problem. I solved it creating my own Button collection that inherits of CollectionBase:

public class ButtonCollection : CollectionBase {

public CustomButton this[int i] {
  get { return InnerList[i] as CustomButton; }
  set { InnerList[i] = value; }
}

public ButtonCollection() {

}

public CustomButton Add(CustomButton bt) {
  InnerList.Add(bt);
  return bt;
}

public void AddRange(CustomButton[] bts) {
  InnerList.AddRange(bts);
}

public void Remove(CustomButton bt) {
  InnerList.Remove(bt);
}

public bool Contains(CustomButton bt) {
  return InnerList.Contains(bt);
}

public CustomButton[] GetValues() {
  CustomButton[] bts = new CustomButton[InnerList.Count];
  InnerList.CopyTo(bts);
  return bts;
}

我还对TypeConverter进行了更改:

I also made changes to the TypeConverter:

public override object ConvertTo(ITypeDescriptorContext context, CultureInfo info, object value, Type destType) {

  if ((destType == typeof(string)) && (value is CustomButton)) {
    CustomButton bt = (CustomButton) value;
    return bt.Name;
  }

  // this helped me a lot
  // here the object needs to know how to create itself
  // Type[0] can be overridden by Type[] { (your constructor parameterTypes) }
  // null can be overridden by objects that will be passed how parameter
  // third parameter is a value indicating if the initialization of the object is or not complete
  else if (destType == typeof(InstanceDescriptor)) {
    return new InstanceDescriptor(
      typeof(CustomButton).GetConstructor(new Type[0]),
      null,
      false
    );
  }

  return base.ConvertTo(context, info, value, destType);
}

TypeConverter装饰器传递给CustomButton类:

TypeConverter Decorator passed to CustomButton class:

[TypeConverter(typeof(CustomButtonConverter))]
public class CustomButton { 
...

我在一个完整的自定义collectionEditor示例中完成了所有这些操作,该示例可以在

I finalized all this following a fully example of custom collectionsEditor that can be found here.

这篇关于如何使用“自定义UITypeEditor C#WindowsFormApplication"在“设计时"中保存收集数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆