Sabyasachi Mukherjee Ответов: 1

Ошибка с текстовым полем со строковым форматом и привязкой в WPF


У меня есть простое представление, содержащее текстовое поле и метку.

<TextBox Text="{Binding MyInt, UpdateSourceTrigger=LostFocus, StringFormat='{}{##.##}'}"/>        
<Label Content="{Binding MyStr2}"/>


И в моем модель представления, У меня есть

private decimal myInt;

public decimal MyInt
{
    get { return myInt; }
    set
    {
        if (value == myInt) { return; }
        myInt = value;               
        OnPropertyChange();
        OnPropertyChange("MyStr2");
    }
}

public string MyStr2
{
    get
    {
        return myInt.ToString("N2", CultureInfo.CreateSpecificCulture("en-IN"));
    }
}


Проще говоря, текст текстового поля привязан к десятичному значению, и метка должна отображать значение в текстовом поле с правильным форматированием.

Поскольку у меня есть LostFocus в качестве текстового поля UpdateSourceTriggerin, я нажимаю TAB, чтобы проверка и привязка работали.

Без атрибута StringFormat в текстовом поле я не могу ввести в него десятичную точку. Следовательно, StringFormat необходим

Поэтому, когда я ввожу десятичное значение, все работает правильно. Метка правильно отображает отформатированный номер.

Когда я ввожу какое-то мусорное не десятичное значение, граница текстового поля становится красной, указывая на ошибку проверки. Но в следующий раз, когда я ввожу некоторые допустимые данные, например 500, в текстовое поле и теряю фокус, текстовое поле становится пустым, а в окне вывода появляется следующая ошибка:

System.Windows.Data Error: 6 : 'StringFormat' converter failed to convert value '500' (type 'Decimal'); fallback value will be used, if available. BindingExpression:Path=MyInt; DataItem='ViewModel' (HashCode=37975124); target element is 'TextBox' (Name='MyIntTextBox'); target property is 'Text' (type 'String') FormatException:'System.FormatException: Input string was not in a correct format.
   at System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
   at System.String.FormatHelper(IFormatProvider provider, String format, ParamsArray args)
   at System.String.Format(IFormatProvider provider, String format, Object[] args)
   at System.Windows.Data.BindingExpression.ConvertHelper(IValueConverter converter, Object value, Type targetType, Object parameter, CultureInfo culture)'


Однако метка отображает 500.00 правильно. Я поместил точки останова в ViewModel, чтобы увидеть, правильно ли обновлено связанное с текстовым полем свойство myInt, и, конечно же, это так. Это происходит только тогда, когда я пытаюсь использовать StringFormat.

Что я уже пробовал:

Я пытался использовать много вариантов StringFormat, но тщетно. На самом деле некоторые значения StringFormat приводят к неустойчивому поведению курсора. Но я вынужден использовать StringFormat, потому что без него я не могу ввести десятичную точку.

Что именно я делаю не так?

Richard MacCutchan

Я не думаю, что формат"##. # # "не может вместить строку "500", поскольку она содержит более 2 значащих цифр. Видеть Строки Настраиваемых Числовых Форматов [^].

Sabyasachi Mukherjee

Но когда я впервые ввожу 500, это работает. Он не работает только тогда, когда я ввожу его сразу после ввода некоторого нечислового значения.

1 Ответов

Рейтинг:
10

Graeme_Grant

Вам не нужно форматировать строку в коде. Вы можете сделать это в Xaml. Также, OnPropertyChange обработка требует очистки. Ниже код будет адресован обоим.

INotifyPropertyChanged обертка


using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfBindingEvents
{
    public abstract class ObservableObject : INotifyPropertyChanged
    {
        public void Notify([CallerMemberName] string caller = "")
        {
            PropertyChanged?.Invoke(this,
                new PropertyChangedEventArgs(caller));

        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

модель данных


namespace WpfBindingEvents
{
    public class FloatFormatModel : ObservableObject
    {
        private float value;
        public float Value
        {
            get { return value; }
            set
            {
                this.value = value;
                Notify();
            }
        }
    }
}

модель представления


namespace WpfBindingEvents
{
    public class MainViewModel
    {
        public FloatFormatModel Model { get; } 
            = new FloatFormatModel { Value = 1234.5678F };
    }
}

код XAML


<Window 

    x:Class="WpfBindingEvents.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

    xmlns:local="clr-namespace:WpfBindingEvents"

    mc:Ignorable="d" WindowStartupLocation="CenterScreen"

    Title="Numeric Formatting Example" Height="350" Width="525">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <TextBlock Text="Float:" 

                   Grid.Row="3" 

                   Margin="10 0"/>
        <TextBlock Text="{Binding Model.Value, StringFormat=N2}"

                   Grid.Column="1"

                   Width="80"/>
    </Grid>

</Window>

Обратите внимание на эту привязку:Text="{Binding Model.Value, StringFormat=N2}"