[英]Custom WinForms data binding with converter not working on nullable type (double?)
In my WinForms application I implemented custom data binding with support for value converters , similar to WPF. 在WinForms应用程序中,我实现了自定义数据绑定,并支持值转换器 ,类似于WPF。
The sample has a new binding class that derives from Binding
and allows to attach a custom converter: 该示例具有一个新的绑定类,该类从
Binding
派生,并允许附加一个自定义转换器:
public class CustomBinding : Binding
{
private readonly IValueConverter _converter;
private readonly object _converterParameter;
private readonly CultureInfo _converterCulture;
public CustomBinding(string propertyName, object dataSource, string dataMember, IValueConverter valueConverter, CultureInfo culture, object converterParameter = null)
: base(propertyName, dataSource, dataMember)
{
if (valueConverter != null)
this._converter = valueConverter;
this.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
this.FormattingEnabled = false;
this._converterCulture = culture;
this._converterParameter = converterParameter;
}
public CustomBinding(string propertyName, object dataSource, string dataMember, IValueConverter valueConverter, object converterParameter = null)
: base(propertyName, dataSource, dataMember)
{
if (valueConverter != null)
this._converter = valueConverter;
this._converterCulture = Thread.CurrentThread.CurrentUICulture;
this._converterParameter = converterParameter;
}
protected override void OnFormat(ConvertEventArgs cevent)
{
if (this._converter != null)
{
var converterdValue = this._converter.Convert(cevent.Value, cevent.DesiredType, _converterParameter, _converterCulture);
cevent.Value = converterdValue;
}
else base.OnFormat(cevent);
}
protected override void OnParse(ConvertEventArgs cevent)
{
if (this._converter != null)
{
var converterdValue = this._converter.ConvertBack(cevent.Value, cevent.DesiredType, _converterParameter, _converterCulture);
cevent.Value = converterdValue;
}
else base.OnParse(cevent);
}
}
There is also the interface IValueConverter
that is similar to the interface of WPF: 还有一个接口
IValueConverter
与WPF的接口类似:
public interface IValueConverter
{
object Convert(object value, Type targetType, object parameter, CultureInfo culture);
object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
With this I'm able to attach an own converter to any (two-way) binding. 这样,我就可以将自己的转换器附加到任何(双向)绑定上。 So far I've built a
TimeSpanStringValueConverter
that allows me to bind a TimeSpan
field to a textbox as well as a InvertBooleanValueConverter
to bind the opposite of a boolean field to any boolean property of any control. 到目前为止,我已经构建了一个
TimeSpanStringValueConverter
,它使我可以将TimeSpan
字段绑定到文本框,还可以将InvertBooleanValueConverter
绑定到布尔字段的对立面到任何控件的任何布尔属性。 They work as expected! 他们按预期工作!
Now I want to bind a property of the type double?
现在我想绑定一个
double?
类型的属性double?
to a textbox Text
field. 到文本框“
Text
字段。 For this I wrote this converter: 为此,我编写了此转换器:
public class NullableDoubleStringValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value != null ? ((double)value).ToString(culture) : String.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string text = Regex.Replace((string)value, @"[^0-9" + culture.NumberFormat.NumberDecimalSeparator + @"]", "");
if (text == String.Empty)
{
return null;
}
double convertedValue;
if (Double.TryParse(text, NumberStyles.Any, culture, out convertedValue))
{
return (double?)convertedValue;
}
return null;
}
}
And I bind it to the textbox this way: 然后通过以下方式将其绑定到文本框:
this.textBox1.DataBindings.Add(new CustomBinding("Text", obj, "MyProperty", new NullableDoubleStringValueConverter())); // obj is the data context object
When I set a break point in the ConvertBack
method of the value converter I can clearly see how my string will be converted to a nullable double value after leaving the textbox, successfully. 当我在值转换器的
ConvertBack
方法中设置断点时,我可以清楚地看到成功离开文本框后,如何将我的字符串转换为可为空的double值。 However, instead of my other cases, it will not update the data context object. 但是,除了我的其他情况,它不会更新数据上下文对象。 And if I set a break point in the
Convert
method of my value converter I can see it will retrieve the initial value of MyProperty
which is null when updating the Text
of the textbox after leaving it. 而且,如果我在值转换器的
Convert
方法中设置了一个断点,我会看到它会检索MyProperty
的初始值,该值在离开文本框后更新Text
框的Text
时将为null。 So, my textbox gets empty after typing any numeric value in it. 因此,我的文本框在其中键入任何数字值后将变为空。
My question is: Why? 我的问题是:为什么? And how can I make it work with nullable types (
double?
)? 我如何使其与可为null的类型(
double?
)一起使用? If I change the type of MyProperty
in the data context object to double
it will accept my changed value. 如果将数据上下文对象中
MyProperty
的类型更改为double
,它将接受更改后的值。 Unfortunately I need the nullable support. 不幸的是,我需要可为空的支持。 So when leaving the textbox empty I want to store null as well as showing an empty text box, when the value was null.
因此,当文本框为空时,我想存储null以及在值为null时显示一个空文本框。
In fact, the bug is not in your code, but in the one you have downloaded ( CustomBinding
). 实际上,该错误不在您的代码中,而是在您已下载的代码中(
CustomBinding
)。 Modify constructors to become 修改构造函数成为
public CustomBinding(string propertyName, object dataSource, string dataMember, IValueConverter valueConverter, object converterParameter = null)
: this(propertyName, dataSource, dataMember, valueConverter, Thread.CurrentThread.CurrentUICulture, converterParameter)
{ }
public CustomBinding(string propertyName, object dataSource, string dataMember, IValueConverter valueConverter, CultureInfo culture, object converterParameter = null)
: base(propertyName, dataSource, dataMember, true)
{
this._converter = valueConverter;
this._converterCulture = culture;
this._converterParameter = converterParameter;
}
and the problem will be solved. 问题就会解决。 The essential part is that
Binding.FormatingEnabled
must be true
in order all this to work (note the last argument to the base call, but you can set it later too). 基本部分是
Binding.FormatingEnabled
必须为true
才能使所有这些正常工作(请注意基本调用的最后一个参数,但您也可以稍后进行设置)。 Also note that I removed 另请注意,我删除了
this.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
line. 线。 The default value for this is
OnValidation
which is applicable for any control. 此项的默认值为
OnValidation
,适用于任何控件。 OnPropertyChanged
is applicable for immediate update controls like check boxes, radio buttons and non editable combo boxes. OnPropertyChanged
适用于即时更新控件,例如复选框,单选按钮和不可编辑的组合框。 In any case, it is better to leave the responsibility of setting this property to the user of the class. 无论如何,最好将设置此属性的责任留给班级的用户。
A side note unrelated to the question: You'd better off not stripping the invalid characters and let the exception to be thrown inside your ConvertBack
method, otherwise you get a weird input values if the user types for instance "1-3" 与问题无关的旁注:最好不要剥离无效字符,并让异常抛出到
ConvertBack
方法内,否则,如果用户键入实例“ 1-3”,则会得到奇怪的输入值
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var text = value != null ? ((string)value).Trim() : null;
return !string.IsNullOrEmpty(text) ? (object)double.Parse(text, NumberStyles.Any, culture) : null;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.