检查文本框中输入的值是WPF中的双数

时间:2018-09-04 00:02:39

标签: c# wpf mvvm

我对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>

3 个答案:

答案 0 :(得分:2)

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

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

希望这会有所帮助!

答案 1 :(得分:2)

解决问题的最简单方法是实施req is not defined

以下是该规则的代码:

this

然后,在XAML中,绑定时必须引用此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); } } 属性。

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中进行。但我不建议这样做,因为用户看到其输入被UI更改非常无聊。

答案 2 :(得分:0)

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