0

検証ルールを使用するアプリケーションを作成していますが、一部の画面では、エラーが発生したフィールドの横に結果のエラーを表示する十分なスペースがないため、アプリケーションの下部にあるステータス バーに配置したいと考えています。分野。

このサンプルは、さまざまなルールを使用して検証し、さまざまな方法でエラーを表示するフォームを提供する Web からつなぎ合わせたいくつかのビットからのものですが、XAML を使用して StatusBarItem にエラー メッセージを取得する方法がわかりません。それを行う簡単な方法があると確信しています。誰でも私を助けてもらえますか?

このサンプルは、Framework 4.0 を使用して VS2010 で作成されました。

MainWindow.xaml

<Window x:Class="SampleValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c="clr-namespace:SWL.Libraries.SysText"
        Title="Sample ValidationRule WPF" Height="350" Width="525"
        Loaded="Window_Loaded" WindowStartupLocation="CenterScreen">
  <Window.Resources>
    <ControlTemplate x:Key="validationTemplate">
      <!--
      <TextBlock Foreground="Red" FontSize="20">***</TextBlock>
      -->
      <DockPanel LastChildFill="True">
        <TextBlock DockPanel.Dock="Right" Foreground="Red" Margin="5" FontSize="8pt" Text="***" />
        <AdornedElementPlaceholder />
      </DockPanel>
    </ControlTemplate>
    <Style x:Key="textBoxInError1" 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>
    <Style x:Key="textBoxInError2"  TargetType="{x:Type TextBox}">
      <Setter Property="Validation.ErrorTemplate">
        <Setter.Value>
          <ControlTemplate>
            <DockPanel LastChildFill="True">
              <TextBlock DockPanel.Dock="Right" Foreground="Red" Margin="5" FontSize="8pt"
                         Text="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
              <Border BorderBrush="Red" BorderThickness="2">
                <AdornedElementPlaceholder Name="MyAdorner" />
              </Border>
            </DockPanel>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
      <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="true">
          <Setter Property="ToolTip"
                  Value="{Binding RelativeSource={RelativeSource Self},
                  Path=(Validation.Errors)[0].ErrorContent}" />
        </Trigger>
      </Style.Triggers>
    </Style>
  </Window.Resources>
  <Grid>
    <TextBlock Height="24" HorizontalAlignment="Left" Margin="36,73,0,0" Name="textBlock1"
               Text="Node Address:" VerticalAlignment="Top" Width="87" />
    <TextBlock Height="24" HorizontalAlignment="Left" Margin="36,112,0,0" Name="textBlock2"
               Text="Node Name:" VerticalAlignment="Top" Width="78" />
    <TextBox Height="24" HorizontalAlignment="Left" Margin="129,70,0,0" Name="textBox1"
             VerticalAlignment="Top" Width="119" TextChanged="textBox1_TextChanged"
             TabIndex="0" Style="{StaticResource textBoxInError2}"
             Validation.ErrorTemplate="{StaticResource validationTemplate}">
      <Binding Path="NodeAddress" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <c:NumberRangeRule Min="1" Max="100" />
        </Binding.ValidationRules>
      </Binding>
    </TextBox>
    <TextBox Height="24" HorizontalAlignment="Left" Margin="129,109,0,0" Name="textBox2"
             VerticalAlignment="Top" Width="119" TextChanged="textBox2_TextChanged"
             TabIndex="1" Style="{StaticResource textBoxInError2}">
      <Binding Path="NodeName" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <c:NameFormatRule MinLength="6" MaxLength="9" />
        </Binding.ValidationRules>
      </Binding>
    </TextBox>
    <StatusBar Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0"
               Name="myStatusBar" VerticalAlignment="Bottom">
      <StatusBarItem x:Name="errorStatusBarItem" Content="No errors" />
    </StatusBar>
    <Button Content="Close" Height="29" HorizontalAlignment="Left" Margin="108,227,0,0"
            Name="btnCLOSE" VerticalAlignment="Top" Width="85" Click="btnCLOSE_Click" TabIndex="3" />
    <Button Content="Apply" Height="29" HorizontalAlignment="Left" Margin="297,227,0,0"
            Name="btnAPPLY" VerticalAlignment="Top" Width="85" Click="btnAPPLY_Click" TabIndex="2" />
  </Grid>
</Window>

MainWindow.cs

using System;
using System.Collections.Generic;  
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SampleValidation {
  /// <summary>
  /// Interaction logic for MainWindow.xaml
  /// </summary>
  public partial class MainWindow : Window {
    public int NodeAddress { get; set; }
    public string NodeName { get; set; }
    public bool IsAllLoaded { get; set; }

    public MainWindow() {
      NodeAddress = 1;
      NodeName = "freddy";
      IsAllLoaded = false;
      InitializeComponent();
      btnAPPLY.Visibility = System.Windows.Visibility.Hidden;
      DataContext = this;
    }

    private void btnAPPLY_Click(object sender, RoutedEventArgs e) {
      // if there are no format errors reported by the validation rules
      Validator.ErrorText = "";
      if (Validator.IsValid(this))
        // Save the data
        btnAPPLY.Visibility = System.Windows.Visibility.Hidden; // hide the button indicating nothing new to save
      else
        MessageBox.Show("Cant Save Changes - Error in form\r\n" + Validator.ErrorText, "Save not allowed", MessageBoxButton.OK, MessageBoxImage.Error);
    }

    private void btnCLOSE_Click(object sender, RoutedEventArgs e) {
      if (btnAPPLY.Visibility != System.Windows.Visibility.Hidden) {
        MessageBoxResult myAnswer = MessageBox.Show("Save Changes?", "Confirmation", MessageBoxButton.YesNoCancel);

        if (myAnswer == MessageBoxResult.Cancel)
          return;
        if (myAnswer == MessageBoxResult.Yes)
          btnAPPLY_Click(sender, e);
      }
      this.Close();
    }

    private void Window_Loaded(object sender, RoutedEventArgs e) {
      IsAllLoaded = true;
    }

    private void ShowModified() {
      if (IsAllLoaded)
          btnAPPLY.Visibility = System.Windows.Visibility.Visible;
    } // ShowModified

    private void textBox2_TextChanged(object sender, TextChangedEventArgs e) {
      ShowModified();
    }

    private void textBox1_TextChanged(object sender, TextChangedEventArgs e) {
      ShowModified();
    }
  } // class MainWindow

  public static class Validator {
    public static string ErrorText { get; set; }

    static Validator() {
      ErrorText = "";
    }

    public static bool IsValid(DependencyObject parent) {
      // Validate all the bindings on the parent
      bool valid = true;
      LocalValueEnumerator localValues = parent.GetLocalValueEnumerator();

      while (localValues.MoveNext()) {
        LocalValueEntry entry = localValues.Current;

        if (BindingOperations.IsDataBound(parent, entry.Property)) {
          Binding binding = BindingOperations.GetBinding(parent, entry.Property);

          if (binding.ValidationRules.Count > 0) {
            BindingExpression expression = BindingOperations.GetBindingExpression(parent, entry.Property);
            expression.UpdateSource();

            if (expression.HasError) {
              ErrorText = expression.ValidationError.ErrorContent.ToString();
              valid = false;
            }
          }
        }
      }

      // Validate all the bindings on the children
      System.Collections.IEnumerable children = LogicalTreeHelper.GetChildren(parent);

      foreach (object obj in children) {
        if (obj is DependencyObject) {
          DependencyObject child = (DependencyObject)obj;

          if (!IsValid(child)) {
            valid = false;
          }
        }
      }
      return valid;
    }
  } // class Validator

ValidationRules.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Windows.Controls;

namespace SWL.Libraries.SysText {
  public class NumberRangeRule : ValidationRule {
    private int _min;
    private int _max;

    public NumberRangeRule() { }

    public int Min {
      get { return _min; }
      set { _min = value; }
    }

    public int Max {
      get { return _max; }
      set { _max = value; }
    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) {
      int val = 0;

      try {
        if (((string)value).Length > 0)
          val = Int32.Parse((String)value);
      } catch (Exception e) {
        return new ValidationResult(false, "Illegal Characters or " + e.Message);
      }

      if ((val < Min) || (val > Max)) {
        return new ValidationResult(false, "Please Enter Number in Range: " + Min + " - " + Max + ".");
      } else {
        return new ValidationResult(true, null);
      }
    }
  }

  public class NameFormatRule : ValidationRule {
    private int _minLength;
    private int _maxLength;

    public NameFormatRule() { }

    public int MinLength {
      get { return _minLength; }
      set { _minLength = value; }
    }

    public int MaxLength 
      get { return _maxLength; }
      set { _maxLength = value; }
    }

    public override ValidationResult Validate(object value, CultureInfo cultureInfo) {
      try {
        if (((string)value).Length > 0) {
          if (((string)value).Length < MinLength || ((string)value).Length > MaxLength)
            return new ValidationResult(false, String.Format ("Enter a string of {0} to {1} characters in length", MinLength, MaxLength));
          return new ValidationResult(true, null);
        }
        return new ValidationResult(true, null);
      } catch (Exception e) {
        return new ValidationResult(false, "Illegal Characters or " + e.Message);
      }
    }
  }
}
4

1 に答える 1

0

更新 最近、マウスがエラー アイコンの上に置かれたときに表示される複数のエラー メッセージを処理する必要がありました。ビューモデルに IDataErrorInfo を実装させました。次に、コントロールごとに 1 つのエラーを保持するために、viewmodel 内に、各コントロールの一意の識別子 (列挙型を使用しただけ) をキーとするクラス レベルのディクショナリを作成しました。次に、文字列型のパブリック プロパティを作成し、それを ErrorText と呼びました。ErrorText の getter は、エラー ディクショナリを繰り返し処理し、すべてのエラーを 1 つの文字列に構築します。

これは例です。微調整が必​​要な場合があります。これは非常に単純化されていることはわかっていますが、方向性を示す必要があります。複雑な検証の場合、作成した ValidationRule オブジェクトを使用して検証し、返された ValidationResult オブジェクトの IsValid プロパティを確認するだけで済みます。

// NOTE:  The enum member name matches the name of the property bound to each textbox
public enum ControlIDs
{
    TextBox1Value = 0,
    TextBox2Value
}

public class MyViewModel : IDataErrorInfo
{
    private readonly Dictionary<ControlIDs, string> errors;

    public string ErrorText
    {
        get
        {
            if (errors.ContainsKey(ControlIDs.TextBox1) && errors.ContainsKey(ControlIDs.TextBox2))
            {
                return "Errors: " + errors[ControlsIDs.TextBox1] + ", " + errors[ControlsIDs.TextBox2];
            }

            if (errors.ContainsKey(ControlIDs.TextBox1))
            {
                return "Error: " + errors[ControlsIDs.TextBox1];
            }

            if (errors.ContainsKey(ControlIDs.TextBox2))
            {
                return "Error: " + errors[ControlsIDs.TextBox2];
            }
        }
    }

    public MyViewModel()
    {
        errors = new Dictionary<ControlIDs, string>();
    }

    private void UpdateErrorCollection(ControlIDs fieldKey, string error)
    {
        if (errors.ContainsKey(fieldKey))
        {
            errors[fieldKey] = error;
        }
        else
        {
            errors.Add(fieldKey, error);
        }

        OnPropertyChanged("ErrorText");
    }

    #region IDataErrorInfo

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

    public string this[string columnName]
    {
        string error = string.Empty;
        if (columnName == ControlIDs.TextBox1Value.ToString())
        {
            if (string.IsNullOrWhiteSpace(TextBox1Value))
            {
                error = "TextBox1 must contain a value";
                UpdateErrorCollection(ControlIDs.TextBox1Value, error);
            }
            else
            {
                errors.Remove(ControlIDs.TextBox1Value);
            }
        }
        else if (columnName == ControlIDs.TextBox2Value))
        {
            if (string.IsNullOrWhiteSpace(TextBox2Value))
            {
                error = "TextBox2 must contain a value";
                UpdateErrorCollection(ControlIDs.TextBox2Value, error);
            }
            else
            {
                errors.Remove(ControlIDs.TextBox2Value);
            }
        }

        // returning null indicates success
        return !string.IsNullOrWhiteSpace(error) ? error : null;
    }

    #endregion
}

StatusBarItem TextBlock を ErrorText プロパティにバインドするだけです。

于 2012-05-31T16:57:28.083 に答える