如何将自定义类型数据绑定到TextBox.Text?

el2*_*ot2 7 c# data-binding textbox typeconverter winforms

我有一个自定义的c#类型(只是一个例子):

public class MyVector
{ 
   public double X {get; set;} 
   public double Y {get; set;} 
   public double Z {get; set;} 
   //...
}
Run Code Online (Sandbox Code Playgroud)

我想将它数据绑定到TextBox.Text:

TextBox textBox;
public MyVector MyVectorProperty { get; set;}
//...
textBox.DataBindings.Add("Text", this, "MyVectorProperty");
Run Code Online (Sandbox Code Playgroud)

基本上我需要转换为自定义值类型的字符串.在文本框中,我想要"x,y,z"之类的东西,可以编辑它来更新矢量类型.我假设我可以通过添加TypeConverter派生类来实现:

public class MyVectorConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, 
                                        Type sourceType)
    {
        if (sourceType == typeof(string))
            return true;
        //...
        return base.CanConvertFrom(context, sourceType);
    }

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

    public override object ConvertFrom(ITypeDescriptorContext context, 
                                       System.Globalization.CultureInfo culture,
                                       object value)
    {
        if (value is string)
        {
            MyVector MyVector;
            //Parse MyVector from value
            return MyVector;
        }
        return base.ConvertFrom(context, culture, value);
    }

    public override object ConvertTo(ITypeDescriptorContext context,
                                     System.Globalization.CultureInfo culture, 
                                     object value, 
                                     Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            string s;
            //serialize value to string s
            return s;
        }
        //...
        return base.ConvertTo(context, culture, value, destinationType);
    }
}
Run Code Online (Sandbox Code Playgroud)

并将其与我的结构相关联:

[TypeConverter(typeof(MyVectorConverter))]
public class MyVector { //... }
Run Code Online (Sandbox Code Playgroud)

这似乎完成了一半的战斗.我可以看到MyVectorConverter被召唤,但有些不对劲.它被调用以查看它是否知道如何转换为字符串,然后调用它来转换为字符串.但是,永远不会查询它是否可以转换FROM字符串,也不会实际进行转换.此外,在文本框中编辑后,立即替换旧值(另一个CanConvertTo和ConvertTo序列,恢复旧值).最终结果是文本框中新键入的条目在应用后立即恢复.

我觉得好像有一些简单的缺失.在那儿?整个项目/方法注定要失败吗?有没有其他人尝试这种疯狂?如何将自定义多部分类型双向绑定到基于字符串的控件?

解决方案:奇怪的是,所需要的只是在Binding对象上启用"格式化".(谢谢Jon Skeet):

textBox.DataBindings.Add("Text", this, "MyVectorProperty"); //FAILS
textBox.DataBindings.Add("Text", this, "MyVectorProperty", true); //WORKS!
Run Code Online (Sandbox Code Playgroud)

奇怪的是,我的MSDN提到的关于这个参数(formattingEnabled)的所有内容是:

"如果格式化显示的数据,则为true;否则为false"

它没有提到要求数据从控制中返回(在这些条件下).

Jon*_*eet 10

得到它了!

将该Binding.FormattingEnabled属性设置为true.这似乎使一切顺利.您可以通过对ControlBindingsCollection.Add方法的重载来执行此操作,该方法最后采用布尔参数.奇怪的是它以前的方式工作,但之前没有,但我的测试应用程序现在肯定有效......

(旧答案如下)

如果你有一个结构而不是一个类的事实在这里很重要,我会不会感到惊讶 - 以及你使用字段而不是属性的方式.

尝试使用自动实现属性的类:

public class MyClass
{ 
   public int IntPart { get; set; } 
   public string StringPart { get; set; }
   //...
}
Run Code Online (Sandbox Code Playgroud)

这可能不是问题的根源,但是使用带有公共字段的可变结构只是在寻找IMO的麻烦.

编辑:正如评论中所提到的,我现在已经开始运行了一个例子.正在使用正确的值引发Binding.Parse.现在找出为什么没有调用TypeConverter ...

编辑:我发现了一篇有用的文章,更详细地描述了绑定.似乎建议类型转换器仅用于将"转换"为另一种类型 - 因此您需要类型转换器string才能知道如何转换为自定义类型.对我而言,这似乎很奇怪,但还有两个选择:

  • 使用Binding的Format和Parse事件进行转换
  • 使类型实现IConvertible

这些都没有完全相同的吸引力,但它们可能足以为您提供解决方案.我确信有一种方法可以使用TypeConverters来实现这一点,但是如果我现在可以看到它,我会感到很震惊.