/// <summary> /// Binds column to <see cref="TextBox"/> with specified value converter and culture info. /// </summary> /// <param name="source">The source column.</param> /// <param name="converter">The value converter.</param> /// <param name="cultureInfo">The culture info.</param> /// <param name="flushErrorMessage">The conversion error message when flushing data from binding to source model.</param> /// <returns>The row binding object.</returns> public static RowBinding <TextBox> BindToTextBox(this Column source, IValueConverter converter, CultureInfo cultureInfo, string flushErrorMessage = null) { source.VerifyNotNull(nameof(source)); converter.VerifyNotNull(nameof(converter)); cultureInfo.VerifyNotNull(nameof(cultureInfo)); return(new RowBinding <TextBox>(onSetup: (v, p) => v.Setup(), onCleanup: (v, p) => v.Cleanup(), onRefresh: (v, p) => { if (!v.GetIsEditing()) { v.Text = Convert(p[source], converter, cultureInfo); } }).BeginInput(TextBox.TextProperty, TextBox.LostFocusEvent) .WithFlushingValidator(v => { try { var result = converter.ConvertBack(v.Text, source.DataType, null, cultureInfo); if (result == DependencyProperty.UnsetValue) { return GetInvalidInputErrorMessage(flushErrorMessage, source.DataType); } } catch (Exception ex) { return ex.Message; } return null; }) .WithFlush(source, (p, v) => { var value = converter.ConvertBack(v.Text, source.DataType, null, cultureInfo); var oldValue = p[source]; if (Equals(oldValue, value)) { return false; } p[source] = value; return true; }) .EndInput()); }