检查文本框中输入的值是否为WPF中的双精度数

问题描述 投票:1回答:3

我是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
    }

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>
c# wpf mvvm
3个回答
2
投票

我修改了您的代码以实现您的目标:

Model.cs

我添加了Observable Base.INotifyPropertyChanged()

     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

希望这可以帮助!


2
投票

解决问题的最简单方法是实现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中进行。但我不赞成这一点,因为用户看到它的输入被UI改变是非常无聊的。


0
投票

最简单的方法是在View层中处理验证 - 使用Extended WPF Toolkit中的DoubleUpDown等控件,而不是通过解析文本字符串来尝试在ViewModel中验证。

© www.soinside.com 2019 - 2024. All rights reserved.