Проверьте, что введенное значение в текстовых полях двойное число в WPF - PullRequest
0 голосов
/ 04 сентября 2018

Я очень новичок в мире WPF, поэтому у меня нет особых идей по этому поводу. В принципе, Я хочу проверить, является ли значение, введенное в текстовые поля, двойным числом или нет. Если значение является двойным числом, измените значение текстового поля результата на NAN, а также измените цвет входного текстового поля на красный.

Может кто-нибудь подсказать мне, как этого добиться?

Model.cs

  public abstract class ObservableBase : INotifyPropertyChanged
    {
        public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
        {
            if (!EqualityComparer<TValue>.Default.Equals(field, default(TValue)) && field.Equals(newValue)) return;
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }


    public abstract class ViewModelBase : ObservableBase
    {
        public bool IsInDesignMode
            => (bool)DesignerProperties.IsInDesignModeProperty
                .GetMetadata(typeof(DependencyObject))
                .DefaultValue;
    }

ViewModel.cs

 public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            if (IsInDesignMode)
            {
                valueA = 2;
                valueB = 3;
                Calc();
            }
        }

        #region Properties

        private int valueA;
        public int ValueA
        {
            get => valueA;
            set
            {
                Set(ref valueA, value);
                Calc();
            }
        }

        private int valueB;
        public int ValueB
        {
            get => valueB;
            set
            {
                Set(ref valueB, value);
                Calc();
            }
        }

        private int valueC;
        public int ValueC
        {
            get => valueC;
            set => Set(ref valueC, value);
        }

        private int valueD;
        public int ValueD
        {
            get => valueD;
            set => Set(ref valueD, value);
        }

        #endregion

        #region Methods

        private void Calc()
        {
            ValueC = valueA + valueB;
            ValueD = valueA * valueB;
        }

        #endregion
    }

1012 * XAML *

<Window x:Class="WPFTestApplication.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:WPFTestApplication.ViewModel"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

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

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="VerticalAlignment" Value="Center"/>
            </Style>
            <Style TargetType="TextBox" x:Key="TextBox">
                <Setter Property="VerticalContentAlignment" Value="Center"/>
                <Setter Property="Margin" Value="10"/>
                <Setter Property="Width" Value="100"/>
                <Setter Property="Height" Value="25"/>
                <Setter Property="Grid.Column" Value="1"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="Silver" />
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style TargetType="TextBox" x:Key="TextBoxA" BasedOn="{StaticResource TextBox}">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="LightBlue" />
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style TargetType="TextBox" x:Key="TextBoxB" BasedOn="{StaticResource TextBox}">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="LightGreen" />
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style TargetType="TextBox" BasedOn="{StaticResource TextBox}"/>
        </Grid.Resources>

        <TextBlock Text="Value A"/>
        <TextBox Text="{Binding ValueA, UpdateSourceTrigger=PropertyChanged}"

                 Style="{StaticResource TextBoxA}"/>

        <TextBlock Text="Value B" Grid.Row="1"/>
        <TextBox Text="{Binding ValueB, UpdateSourceTrigger=PropertyChanged}"

                 Style="{StaticResource TextBoxB}"

                 Grid.Row="1"/>

        <TextBlock Text="Value C" Grid.Row="2"/>
        <TextBox Text="{Binding ValueC}"

                 IsReadOnly="True"

                 Grid.Row="2"/>

        <TextBlock Text="Value D" Grid.Row="3"/>
        <TextBox Text="{Binding ValueD}"

                 IsReadOnly="True"

                 Grid.Row="3"/>


    </Grid>
</Window>

Ответы [ 3 ]

0 голосов
/ 04 сентября 2018

Самый простой способ решить вашу проблему - реализовать ValidationRule.

Вот код для правила:

public class DoubleValidation : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        //You can do whatever you want here
        double check;
        if (!double.TryParse(value.ToString(),out check))
        {
            //ValidationResult(false,*) => in error
            return new ValidationResult(false, "Please enter a number");
        }
        //ValidationResult(true,*) => is ok
        return new ValidationResult(true, null);
    }
}

Тогда в вашем XAML вы должны ссылаться на это ValidationRule при связывании, что позволяет вам получить свойство Validation.HasError в вашем стиле.

<TextBox Validation.ErrorTemplate="{x:Null}">
    <TextBox.Text>
        <Binding Path="ValueB" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:DoubleValidation/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
    <TextBox.Style>
        <Style BasedOn="{StaticResource TextBoxB}" TargetType="TextBox">
              <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="True">
                    <Setter Property="Background" Value="Red"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

Поскольку Error добавит красную рамку к TextBox, я добавлю Validation.ErrorTemplate="{x:Null}", чтобы сохранить полный контроль.

Если вы хотите изменить значение Textbox на NaN, вы должны сделать это в вашем ViewModel. Но я бы не рекомендовал этого, поскольку пользователю очень скучно видеть, как его входные данные изменяются пользовательским интерфейсом.

0 голосов
/ 04 сентября 2018

Самый простой способ сделать это - обработать проверку в слое View - используя элемент управления, такой как DoubleUpDown из Extended WPF Toolkit , вместо попытки проверки в ViewModel путем анализа текстовой строки. .

0 голосов
/ 04 сентября 2018

Я изменил ваш код для достижения вашей цели:

Model.cs

Я добавил ObservableBase.NotifyPropertyChanged ()

     public abstract class ObservableBase : INotifyPropertyChanged
        {
            public void Set<TValue>(ref TValue field, TValue newValue, [CallerMemberName] string propertyName = "")
            {
                if (!EqualityComparer<TValue>.Default.Equals(field, default(TValue)) && field.Equals(newValue)) return;
                field = newValue;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }

            public event PropertyChangedEventHandler PropertyChanged;

            public void NotifyPropertyChanged(string propertyName)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }


        public abstract class ViewModelBase : ObservableBase
        {
            public bool IsInDesignMode
                => (bool)DesignerProperties.IsInDesignModeProperty
                    .GetMetadata(typeof(DependencyObject))
                    .DefaultValue;
        }

Тогда ваша ViewModel будет выглядеть следующим образом, вы видите, что я изменил типы с int на string, затем добавил флаги проверки, трюк, чтобы проверить, является ли ввод double или нет, должен использовать double.TryParse.

 public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            valueAisValid = true;
            valueBisValid = true;
            if (IsInDesignMode)
            {
                Calc();
            }
        }

        #region Properties

        private string valueA;
        public string ValueA
        {
            get => valueA;
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    Set(ref valueA, value);
                    Set(ref valueAisValid, double.TryParse(ValueA, out double d));
                    NotifyPropertyChanged(nameof(ValueAIsValid));
                    Calc();
                }
            }
        }

        private bool valueAisValid;
        public bool ValueAIsValid => valueAisValid;

        private string valueB;
        public string ValueB
        {
            get => valueB;
            set
            {
                if (!string.IsNullOrEmpty(value))
                {
                    Set(ref valueB, value);
                    Set(ref valueBisValid, double.TryParse(ValueB, out double d));
                    NotifyPropertyChanged(nameof(ValueBIsValid));
                    Calc();
                }
            }
        }

        private bool valueBisValid;
        public bool ValueBIsValid => valueBisValid;

        private string valueC;
        public string ValueC
        {
            get => valueC;
            set => Set(ref valueC, value);
        }

        private string valueD;
        public string ValueD
        {
            get => valueD;
            set => Set(ref valueD, value);
        }

        public bool InputsValid => ValueAIsValid && ValueBIsValid;

        #endregion

        #region Methods

        private void Calc()
        {
            if (InputsValid)
            {
                double sum = Convert.ToDouble(valueA) + Convert.ToDouble(valueB);
                double product = Convert.ToDouble(valueA) * Convert.ToDouble(valueB);
                ValueC = sum.ToString(CultureInfo.InvariantCulture);
                ValueD = product.ToString(CultureInfo.InvariantCulture);
            }
            else
            {
                ValueC = "NAN";
                ValueD = "NAN";
            }
        }

        #endregion
    }

Теперь вот новый парень, познакомьтесь с BoolToBackgroundColorConverter.

namespace WPFTestApplication
{
    public class BoolToBackgroundColorConverter: IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value != null && !(bool)value)
            {
                return new SolidColorBrush(Colors.Red);
            }
            else if(value != null && (bool)value && parameter != null)
            {
                return (SolidColorBrush)parameter;
            }
            else
            {
                return new SolidColorBrush(Colors.White);
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

Теперь ваш xaml будет выглядеть так:

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

    <Window.Resources>
        <local:BoolToBackgroundColorConverter x:Key="BoolToBackgroundColorConverter"/>
    </Window.Resources>

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.Resources>
            <SolidColorBrush x:Key="LightGreen" Color="LightGreen" />
            <SolidColorBrush x:Key="LightBlue" Color="LightBlue" />
            <SolidColorBrush x:Key="White" Color="White" />
            <Style TargetType="TextBlock">
                <Setter Property="VerticalAlignment" Value="Center"/>
            </Style>
            <Style TargetType="TextBox" x:Key="TextBox">
                <Setter Property="VerticalContentAlignment" Value="Center"/>
                <Setter Property="Margin" Value="10"/>
                <Setter Property="Width" Value="100"/>
                <Setter Property="Height" Value="25"/>
                <Setter Property="Grid.Column" Value="1"/>
            </Style>
             <Style TargetType="TextBox" x:Key="TextBoxA" BasedOn="{StaticResource TextBox}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="{Binding ValueAIsValid, Converter={StaticResource BoolToBackgroundColorConverter}, ConverterParameter={StaticResource LightBlue}}" />
                </Trigger>
            </Style.Triggers>
            <Setter Property="Background" Value="{Binding ValueAIsValid, Converter={StaticResource BoolToBackgroundColorConverter}, ConverterParameter={StaticResource White}}" />
        </Style>
        <Style TargetType="TextBox" x:Key="TextBoxB" BasedOn="{StaticResource TextBox}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="{Binding ValueBIsValid, Converter={StaticResource BoolToBackgroundColorConverter}, ConverterParameter={StaticResource LightGreen}}" />
                </Trigger>
            </Style.Triggers>
            <Setter Property="Background" Value="{Binding ValueBIsValid, Converter={StaticResource BoolToBackgroundColorConverter}, ConverterParameter={StaticResource White}}" />
        </Style>
            <Style TargetType="TextBox" BasedOn="{StaticResource TextBox}"/>
        </Grid.Resources>

        <TextBlock Text="Value A"/>
        <TextBox Text="{Binding ValueA, UpdateSourceTrigger=PropertyChanged}"

                 Style="{StaticResource TextBoxA}"/>

        <TextBlock Text="Value B" Grid.Row="1"/>
        <TextBox Text="{Binding ValueB, UpdateSourceTrigger=PropertyChanged}"

                 Style="{StaticResource TextBoxB}"

                 Grid.Row="1"/>

        <TextBlock Text="Value C" Grid.Row="2"/>
        <TextBox Text="{Binding ValueC}"

                 IsReadOnly="True"

                 Grid.Row="2"/>

        <TextBlock Text="Value D" Grid.Row="3"/>
        <TextBox Text="{Binding ValueD}"

                 IsReadOnly="True"

                 Grid.Row="3"/>


    </Grid>

Выход:

enter image description here enter image description here

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...