防止属性被调用两次

时间:2017-06-07 11:10:56

标签: c# wpf

我有一个带有几个文本字段的窗口和一个确定和取消按钮。当我单击“确定”时,它需要验证我的字段并在它们有效时执行它们并显示错误消息(如果它们不存在。)

在我的ViewModel中,我有

public ICommand OKCommand { get; private set; }
public Action ErrorAction { get; set; }

OKCommand = new BaseCommand(_ =>
{               
    if (string.IsNullOrEmpty(ErrorMessage))
    {
        // Do stuff with the contents of the fields
        ...
    }
    else ErrorAction();
});

public string ErrorMessage
{
    get
    {
        // Gets the error message for the fields
        ...
    }
}

在我的代码背后,我有

if (ViewModel.ErrorAction == null) ViewModel.ErrorAction = new Action(() => MessageDialog.ShowError(ViewModel.ErrorMessage));

我的问题是ErrorMessage在出现错误时被调用两次,首先是OKCommand,再次是ErrorAction

我能想到的唯一解决方案是

  1. 接受第二个电话 - 这不是世界末日。
  2. 确定OKCommand中是否存在错误,并在适当时设置ErrorMessage
  3. 像这样的东西

    private bool HasError
    {
        get
        {
            // Do the same as ErrorMessage but populate ErrorMessage and return a bool
            ...
        }
    }
    
    OKCommand = new BaseCommand(_ =>
    {               
        if (!HasError)
        {
            // Do stuff with the contents of the fields
            ...
        }
        else ErrorAction();
    });
    

    虽然两种方法都工作,但我认为两者都不是很好 - 第一次有第二次调用,第二次增加了一个间接级别。还有其他选择吗?

2 个答案:

答案 0 :(得分:0)

有一种验证TextBox文本的简单方法:

它叫做 ValidationRule

You can directly see that there is an error(Error in MouseOverMessage) and the Button is disabled

<Window x:Class="TestWpf.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:TestWpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:MyValidatorProperties x:Key="properties"/>
        <local:MyCustomValidationRule x:Key="validator" />
        <Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="BorderBrush" Value="Red"/>
                    <Setter Property="BorderThickness" Value="2" />
                    <Setter Property="ToolTip"
                         Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <ControlTemplate x:Key="validationTemplate">
            <DockPanel>
                <TextBlock Foreground="Red" FontSize="17">!</TextBlock>
                <AdornedElementPlaceholder/>
            </DockPanel>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <TextBox x:Name="tbName" Height="23" Validation.ErrorTemplate="{StaticResource validationTemplate}" Style="{StaticResource textBoxInError}" Margin="10,10,349,286">
            <TextBox.Text>
                <Binding Path="myName" Source="{StaticResource properties}"
                         UpdateSourceTrigger="PropertyChanged" >
                    <Binding.ValidationRules>
                        <local:MyCustomValidationRule Type="myName" ValidatesOnTargetUpdated="True" />
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <Button x:Name="btnCreate" Content="Create" Width="58" Height="23" Margin="174,10,285,286" >
            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="IsEnabled" Value="False"/>
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding Path=(Validation.HasError), ElementName=tbRepositoryName}" Value="False"/>
                            </MultiDataTrigger.Conditions>
                            <Setter Property="IsEnabled" Value="True"/>
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
    </Grid>
</Window>

代码背后:

ValidatiorClass:

using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Controls;


namespace TestWpf
{
    class MyCustomValidationRule : ValidationRule
    {
        public string Type { get; set; }
        public override ValidationResult Validate(object p_value, CultureInfo p_cultureInfo)
        {
            switch (Type)
            {
                case "myName":
                    string a_strValue = p_value as string;
                    if (!string.IsNullOrEmpty(a_strValue))
                    {
                        Match a_match = Regex.Match((string)p_value, @"^[a-zA-Z\d]+$");
                        return a_match.Success ? new ValidationResult(true, "Name is valid!") : new ValidationResult(false, $"Input should be a Valid Name (a-z, A-Z, 0-9)");
                    }
                    return new ValidationResult(false, "Empty name!");
                default:
                    return new ValidationResult(false, $"UnkownValidation Parameter: " + Type);
            }
        }
    }
}

绑定到TextBox的属性:

using System.ComponentModel;

namespace TestWpf
{
    class MyValidatorProperties : INotifyPropertyChanged
    {
        private string m_myName = "";

        public string myName
        {
            get
            {
                return m_myName;
            }
            set
            {
                if (m_myName != value)
                {
                    m_myName = value;
                    OnPropertyChanged("myName");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string info)
        {
            PropertyChanged?.Invoke(null, new PropertyChangedEventArgs(info));
        }
    }
}

<强> PS: 如果您不想禁用Button并显示消息,则可以将Button替换为:

<Button x:Name="btnCreate" Content="Create" Width="58" Height="23" Click="btnCreate_Click" />

并添加方法:

private void btnCreate_Click(object sender, RoutedEventArgs e)
{
   if(System.Windows.Controls.Validation.GetHasError(tbName))
   {
      //Show Message
   }
}

答案 1 :(得分:0)

最后我决定,鉴于没有任何选项明显优于我目前的解决方案,我会坚持这一点。

为了将来参考,此article描述了数据验证的替代方法。但是,不幸的是,我的要求意味着这对我来说不是一个简单的选择。