I am creating a custom UWP user control. I am two way binding the text in a TextBox with an IValueConverter to convert a string to decimal and back. My converter is converting the decimal to a string in the Textbox when loading the data from behind. However, I am unable to trigger my converter's ConvertBack method when the Textbox loses focus inside my custom control like the usual behavior of a regular Textbox control.
Is there a way to notice the TextBox unfocus and trigger the conversion back to the decimal inside my usercontrol back to my model data though its dependency property ?
Here is my UserControl.
<UserControl
<Grid Margin="15,0,15,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*"/>
<ColumnDefinition Width="5*"/>
</Grid.ColumnDefinitions>
<TextBox
x:Name="textBox"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
Header="{x:Bind Header}"
Text="{x:Bind Text}"
IsEnabled="{x:Bind IsControlEnabled}"/>
<TextBlock
Grid.Row="1"
Grid.Column="0"
Foreground="RosyBrown"
Text="{x:Bind InspectionValidation}"/>
</Grid>
</UserControl>
Here is it's code-behind
public sealed partial class FrmTextBox : UserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.Register("Header", typeof(string),
typeof(FrmComboBox), new PropertyMetadata(null));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string),
typeof(FrmComboBox), new PropertyMetadata(null));
public static readonly DependencyProperty
InspectionValidationProperty =
DependencyProperty.Register("InspectionValidation", typeof(string)
, typeof(FrmInspection), null);
public static readonly DependencyProperty
IsLayoutEnabledProperty =
DependencyProperty.Register("IsLayoutEnabled", typeof(int?)
, typeof(FrmInspection), null);
public string Header
{
get { return (string)GetValue(HeaderProperty); }
set { SetValue(HeaderProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
}
}
public string InspectionValidation
{
get => (string) GetValue(InspectionValidationProperty);
set =>SetValue( InspectionValidationProperty, value);
}
public int? IsLayoutEnabled
{
get => (int?) GetValue(IsLayoutEnabledProperty);
set
{
IsControlEnabled = (value == -1) ? true : false;
SetValue( IsLayoutEnabledProperty, value);
}
}
private bool isControlEnabled { get; set; }
public bool IsControlEnabled
{
get => isControlEnabled;
set
{
if (value == isControlEnabled) return;
isControlEnabled = value;
OnPropertyChanged();
}
}
public FrmTextBox()
{
this.InitializeComponent();
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
// Raise the PropertyChanged event, passing the name of the property whose value has changed.
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Here is my IValueConverter
public class StringToDecimalConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value != null)
return value.ToString();
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
try
{
if (value != null)
{
Decimal newValue;
Decimal.TryParse((string) value, out newValue);
return newValue;
}
return null;
}
catch
{
return null;
}
}
}
This is my Xaml implementation of the user control.
<controls:FrmTextBox
Grid.Row="1"
Grid.Column="1"
Header="Labor Count"
Text="{x:Bind ViewModel.Current.LaborCount, Mode=TwoWay, Converter={StaticResource StringToDecimal}}"
InspectionValidation=""
IsLayoutEnabled="-1">
</controls:FrmTextBox>