Reputation: 59
I have custom TextBox that only accepts float as input. I bind it to float property (of custom dependency property) using two-way mode. It uses custom converter to do the string conversion to float and vice versa. If i don't format the string, obviously it will display such value such as 3,141592653... which has too many digits behind comma, i want to display 2 decimal places but keep the actual data of the precise value. however, when i tried to run it, string formatting does not work if i set the converter explicitly, unless i remove the converter property it will work. So here i can choose either keep the converter or the string formatting.
I need that converter because wpf default conversion is not enough. It convert empty string as 0 and accept both dot and comma as the delimiter of the decimal. So how do i make my custom textbox to do both stringformat and converter work?
Below is the relevant code of my custom TextBox (called DoubleBox)
My custom TextBox XAML (DoubleBox.XAML)
<TextBox ...
Name="Root">
<TextBox.Text>
<Binding ElementName="Root"
Path="DoubleValue"
Mode="TwoWay"
UpdateSourceTrigger="Explicit"
Converter="{StaticResource DoubleToString}"
StringFormat="{}{0:f2}">
<Binding.ValidationRules>
<validationrules:MyDoubleValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
My custom TextBox code-behind (DoubleBox.XAML.cs)
public partial class DoubleBox : TextBox
{
// constructor
public double DoubleValue
{
get { return (double)GetValue(DoubleValueProperty); }
set { SetValue(DoubleValueProperty, value); }
}
public static readonly DependencyProperty DoubleValueProperty =
DependencyProperty.Register(nameof(DoubleValue), typeof(double), typeof(DoubleBox), new PropertyMetadata(0.0));
// method that does the binding update source trigger
// (when focus is lost and enter key is pressed)
}
My double to string converter
public class DoubleToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((double)value).ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string str = (string)value;
if (string.IsNullOrEmpty(str))
return 0;
str = str.Replace('.', ',');
if (str.StartsWith(','))
str = "0" + str;
return double.Parse(str);
}
}
Edit for more clarification:
I have tried formatting the double value inside the double to string conversion method. i could round the double first before converting it to string i.e. return Math.Round(((double)value), 2).ToString();
and it display 2 decimal float correctly but remember this is a textbox: the user can modify the value from the textbox itself so it is a TwoWay data binding.
As soon i give my focus to the TextBox it does not display all the floating point precision, it still display 2 decimal float so when i try to lose the focus, the TextBox convert it back to the source property of double as is, which is the formatted value, which is 2 decimal float, so precision is lost so yes this approach does not work for TwoWay binding.
Below is a video link of how it behave in my project if i format the string inside the double to string conversion method: https://media.giphy.com/media/7wWVlzl3orIeVl3G2B/giphy.gif
Upvotes: 0
Views: 915
Reputation: 59
i have solved this problem by looking it from other point of view. It exactly does what i want which is display the formatted value (only when focus is lost) and does the conversion
Instead of trying to make both stringformat and converter works, i used triggers that is activated when focus is lost. The trigger sets the Text property to the formatted string so the text display the formatted string only when it does not have focus, but when focus is given, it displays the actual value.
Below is the updated XAML of the DoubleBox.XAML. Actually it is a UserControl now in my code and put the actual TextBox inside the UserControl, no longer modified TextBox but the method still the same by using trigger that display the formatted string when focus is lost
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Text">
<Setter.Value>
<Binding ElementName="Root"
Path="DoubleValue"
Mode="TwoWay"
Converter="{StaticResource DoubleToString}"
UpdateSourceTrigger="Explicit">
<Binding.ValidationRules>
<validationRules:DoubleValidationRule/>
</Binding.ValidationRules>
</Binding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Text">
<Setter.Value>
<Binding ElementName="Root"
Path="DoubleValue"
Mode="OneWay"
StringFormat="{}{0:f2}">
</Binding>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
Upvotes: 1