WPF - 验证 - 如何显示工具提示并禁用“运行”按钮

4

你好,我需要验证应用程序中的一些文本框。我决定使用验证规则“DataErrorValidationRule”。因此,在我的类中,我实现了IDataErrorInfo接口并编写了适当的函数。在我的xaml代码中,我将绑定和验证规则添加到文本框中。

 <TextBox x:Name="txtName" Grid.Column="3" Grid.Row="1"  TextAlignment="Center" >
                        <TextBox.Text>
                            <Binding Path="Name" >
                                <Binding.ValidationRules>
                                    <DataErrorValidationRule></DataErrorValidationRule>
                                </Binding.ValidationRules>
                            </Binding>
                        </TextBox.Text>
                    </TextBox>

这个文本框的验证是正确的-我的意思是,如果数据错误,文本框上会出现红色边框。然而,我需要做的是在该文本框上显示工具提示,但更重要的是,如果任何文本框有错误数据,我必须禁用“运行”按钮。最好的方法是什么?

编辑 第一个问题已解决,但我有另一个问题。我需要使用MultiBindings来验证我的按钮。所以我做了如下操作

 <Button x:Name="btnArrange"  Grid.Column="0"  Content="Rozmieść" Click="btnArrange_Click" >
                <Button.Style>
                    <Style TargetType="Button">
                        <Style.Triggers>
                            <DataTrigger Value="False">
                                <DataTrigger.Binding>
                                    <MultiBinding Converter="{StaticResource BindingConverter}">
                                        <Binding ElementName="txtName" Path="Validation.HasError" />
                                        <Binding ElementName="txtSurname" Path="Validation.HasError"/>
                                        <Binding ElementName="txtAddress" Path="Validation.HasError"/>

                                    </MultiBinding>
                                </DataTrigger.Binding>
                                <Setter Property="IsEnabled" Value="False"/>

                            </DataTrigger>
                        </Style.Triggers>
                    </Style>        
                </Button.Style>

        </Button>

我的转换器看起来像这样。
 public  class Converters : IMultiValueConverter
{

    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if(values !=null && values.Length > 0)
        {


            if (values.Cast<type>().Count(val => val) > 0)
                return false;
            return true;
        }
        return false;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }

    #endregion
}

但是在这个转换器中,我得到了InvalidCastException的错误。在这种情况下,什么是适当的转换方式?我认为HasError是一个布尔类型,所以我应该将其转换为布尔类型。


什么是“类型”?请用“if(values.Cast<bool>()。Any(val => val))”替换它。 - vortexwolf
3个回答

16

如果想要在工具提示中显示错误信息,请将以下内容添加到您的Application.Resources中:

<Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
  <Style.Triggers>
    <Trigger Property="Validation.HasError" Value="true">
      <Setter Property="ToolTip"
        Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
    </Trigger>
  </Style.Triggers>
</Style>

( 例子来自 http://msdn.microsoft.com/en-us/library/system.windows.controls.validation.errortemplate.aspx )

为了启用/禁用一个按钮,你可以使用类似以下的代码

<Button x:Name="btnOK" Content="OK" IsDefault="True" Click="btnOK_Click">
  <Button.Style>
    <Style TargetType="{x:Type Button}">
      <Setter Property="IsEnabled" Value="false" />
      <Style.Triggers>
        <MultiDataTrigger>
          <MultiDataTrigger.Conditions>
            <Condition Binding="{Binding ElementName=txt1, Path=(Validation.HasError)}" Value="false" />
            <Condition Binding="{Binding ElementName=txt2, Path=(Validation.HasError)}" Value="false" />
          </MultiDataTrigger.Conditions>
          <Setter Property="IsEnabled" Value="true" />
        </MultiDataTrigger>
      </Style.Triggers>
    </Style>
  </Button.Style>
</Button>

或者您可以实现ICommand并使用命令绑定。

编辑

这里是一个完全工作的示例。它显示一个带有两个文本框的窗口。只有当两个文本框都非空时,按钮才启用。创建一个名为ValidationDemo的项目,并将以下文件放入其中:

MainWindow.xaml:

<Window x:Class="ValidationDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="146" Width="223">
  <Window.Resources>
    <Style TargetType="{x:Type TextBox}">
      <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
          <Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </Window.Resources>
  <Grid>
    <Label Content="A" Height="28" HorizontalAlignment="Left" Margin="46,7,0,0" Name="label1" VerticalAlignment="Top" />
    <TextBox Name="txtA" Text="{Binding Path=TextA, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Height="23" HorizontalAlignment="Left" Margin="69,12,0,0" VerticalAlignment="Top" Width="120" />
    <Label Content="B" Height="28" HorizontalAlignment="Left" Margin="46,39,0,0" Name="label2" VerticalAlignment="Top" />
    <TextBox Name="txtB" Text="{Binding Path=TextB, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" Height="23" HorizontalAlignment="Left" Margin="69,41,0,0" VerticalAlignment="Top" Width="120" />
    <Button Name="btnOk" Content="OK" Height="23" HorizontalAlignment="Left" Margin="114,70,0,0" VerticalAlignment="Top" Width="75" Click="btnOk_Click">
      <Button.Style>
        <Style TargetType="{x:Type Button}">
          <Setter Property="IsEnabled" Value="false" />
          <Style.Triggers>
            <MultiDataTrigger>
              <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding ElementName=txtA, Path=(Validation.HasError)}" Value="false" />
                <Condition Binding="{Binding ElementName=txtB, Path=(Validation.HasError)}" Value="false" />
              </MultiDataTrigger.Conditions>
              <Setter Property="IsEnabled" Value="true" />
            </MultiDataTrigger>
          </Style.Triggers>
        </Style>
      </Button.Style>
    </Button>
  </Grid>
</Window>

MainWindow.xaml.cs:

using System.Windows;

namespace ValidationDemo
{
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window
  {

    private Model model = new Model();

    public MainWindow()
    {
      InitializeComponent();
      this.DataContext = this.model;
    }

    private void btnOk_Click(object sender, RoutedEventArgs e)
    {
      Application.Current.Shutdown();
    }
  }
}

Model.cs:

using System;
using System.ComponentModel;

namespace ValidationDemo
{
  public class Model : INotifyPropertyChanged, IDataErrorInfo
  {
    public event PropertyChangedEventHandler PropertyChanged;

    private string textA = string.Empty;
    public string TextA
    {
      get
      {
        return this.textA;
      }
      set
      {
        if (this.textA != value)
        {
          this.textA = value;
          this.OnPropertyChanged("TextA");
        }
      }
    }

    private string textB = string.Empty;
    public string TextB
    {
      get
      {
        return this.textB;
      }
      set
      {
        if (this.textB != value)
        {
          this.textB = value;
          this.OnPropertyChanged("TextB");
        }
      }
    }

    public string Error
    {
      get { throw new NotImplementedException(); }
    }

    public string this[string columnName]
    {
      get
      {
        string result = string.Empty;
        switch (columnName)
        {
          case "TextA":
            if (string.IsNullOrEmpty(this.textA))
            {
              result = "'A' must not be empty";
            }
            break;
          case "TextB":
            if (string.IsNullOrEmpty(this.textA))
            {
              result = "'B' must not be empty";
            }
            break;
        }
        return result;
      }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
      if (this.PropertyChanged != null)
      {
        this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }

  }

}

不幸的是它没有起作用。尽管我的一个文本框验证失败,但我的“确定”按钮仍然可用。 - stylus

5
<Window.Resources>
    <Style x:Key="ElementInError" TargetType="{x:Type FrameworkElement}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip"
                    Value="{Binding (Validation.Errors)[0].ErrorContent, RelativeSource={x:Static RelativeSource.Self}}"/>
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<!-- ... -->
<TextBox x:Name="txtName" Style="{StaticResource ElementInError}">
    <!-- ... -->        
</TextBox>
<!-- ... --> 
        <Button x:Name="OkButton" Content="Ok" Margin="5" Click="OkButton_Click">
            <Button.Style>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding ElementName=txtName,Path=(Validation.HasError)}" Value="True">
                            <Setter Property="IsEnabled" Value="False" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>

谢谢您的回答,您能再看一下我的问题吗?我已经编辑过了。 - stylus

2

如果您创建了验证摘要,您可以将“运行”按钮的IsEnabled属性绑定到其HasErrors属性。

由于您希望在HasErrors为false时IsEnabled为true(反之亦然),因此需要使用中间属性或转换器。


1
我该如何创建验证摘要? - stylus
@validator - 这里有一个 - http://codeblitz.wordpress.com/2009/05/12/wpf-validation-summary-control/ - 我之前搞混了Silverlight,抱歉。 - ChrisF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接