私の標準的な例では、2 つのタブがあり、最初のタブにはボタンがあり、2 番目のタブには検証ルールにバインドされたテキスト ボックスがあります。ボタンがクリックされると、検証が失敗し、Validation.Error イベントが発生する原因となるアクションが発生します。ただし、イベントは 2 番目のタブをクリックしたときにのみ発生します。
これが私にとって非常に重要な理由は、複数のタブで発生する複雑な検証を行うフォームがあり、エラーを含むタブを強調表示したいからです。特に、フォームが最初に読み込まれたときにエラーを表示したいのです。
フォームが読み込まれたときに検証を強制的に実行する手法を既に使用しましたが、ボタンがクリックされたときにフォームが読み込まれたときに起動しない理由がわかりません。
私のテストケースのXAML:
<Window x:Class="WpfApplication1.TabsDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="Tabs" Height="300" Width="300" Validation.Error="Window_Error">
<TabControl Grid.Row="0">
<TabItem>
<TabItem.Header>First</TabItem.Header>
<StackPanel Margin="5">
<Button Click="Button_Click">Clear the second textbox</Button>
</StackPanel>
</TabItem>
<TabItem>
<TabItem.Header>MyDataItem</TabItem.Header>
<TextBox>
<TextBox.Text>
<local:ValidationBinding Path="MyDataItem" UpdateSourceTrigger="LostFocus">
<local:ValidationBinding.ValidationRules>
<local:ValidateText />
</local:ValidationBinding.ValidationRules>
</local:ValidationBinding>
</TextBox.Text>
</TextBox>
</TabItem>
</TabControl>
</Window>
私のコードビハインド:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
public partial class TabsDemo : Window
{
public TabsDemo()
{
InitializeComponent();
DataContext = new MyViewModel();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
(DataContext as MyViewModel).MyDataItem = String.Empty;
}
private void Window_Error(object sender, ValidationErrorEventArgs e)
{
MessageBox.Show("Validation Error : " + e.Error.RuleInError);
}
}
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _myDataItem = "Default Value";
public string MyDataItem
{
get { return _myDataItem; }
set
{
if (_myDataItem != value)
{
_myDataItem = value;
NotifyPropertyChanged(new PropertyChangedEventArgs("MyDataItem"));
}
}
}
private void NotifyPropertyChanged(PropertyChangedEventArgs args)
{
if (PropertyChanged != null)
PropertyChanged(this, args);
}
}
}
完全を期すために、検証バインディング マークアップ拡張機能を次に示します。
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Markup;
namespace WpfApplication1
{
public class ValidationBinding : MarkupExtension
{
private readonly Binding _binding = new Binding();
private DependencyObject _dependencyObject;
private DependencyProperty _dependencyProperty;
public ValidationBinding()
{
_binding.ValidatesOnDataErrors = true;
_binding.ValidatesOnExceptions = true;
_binding.NotifyOnValidationError = true;
}
public ValidationBinding(string path)
{
_binding.Path = new PropertyPath(path);
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
var valueTarget = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
_dependencyObject = valueTarget.TargetObject as DependencyObject;
_dependencyProperty = valueTarget.TargetProperty as DependencyProperty;
var element = _dependencyObject as FrameworkElement;
if (element != null)
{
if (element.IsLoaded)
ForceValidation();
else
element.Loaded += (sender, args) => ForceValidation();
}
else
{
ForceValidation();
}
Debug.WriteLine("MarkupExtension.ProvideValue called for element " + element.Name);
return _binding.ProvideValue(serviceProvider);
}
private void ForceValidation()
{
BindingOperations.GetBindingExpression(_dependencyObject, _dependencyProperty).UpdateSource();
}
public object FallbackValue
{
get { return _binding.FallbackValue; }
set { _binding.FallbackValue = value; }
}
public string StringFormat
{
get { return _binding.StringFormat; }
set { _binding.StringFormat = value; }
}
public object TargetNullValue
{
get { return _binding.TargetNullValue; }
set { _binding.TargetNullValue = value; }
}
public string BindingGroupName
{
get { return _binding.BindingGroupName; }
set { _binding.BindingGroupName = value; }
}
public Collection<ValidationRule> ValidationRules
{
get { return _binding.ValidationRules; }
}
public bool ValidatesOnExceptions
{
get { return _binding.ValidatesOnExceptions; }
set { _binding.ValidatesOnExceptions = value; }
}
public bool ValidatesOnDataErrors
{
get { return _binding.ValidatesOnDataErrors; }
set { _binding.ValidatesOnDataErrors = value; }
}
public PropertyPath Path
{
get { return _binding.Path; }
set { _binding.Path = value; }
}
public string XPath
{
get { return _binding.XPath; }
set { _binding.XPath = value; }
}
public BindingMode Mode
{
get { return _binding.Mode; }
set { _binding.Mode = value; }
}
public UpdateSourceTrigger UpdateSourceTrigger
{
get { return _binding.UpdateSourceTrigger; }
set { _binding.UpdateSourceTrigger = value; }
}
public bool NotifyOnSourceUpdated
{
get { return _binding.NotifyOnSourceUpdated; }
set { _binding.NotifyOnSourceUpdated = value; }
}
public bool NotifyOnTargetUpdated
{
get { return _binding.NotifyOnTargetUpdated; }
set { _binding.NotifyOnTargetUpdated = value; }
}
public bool NotifyOnValidationError
{
get { return _binding.NotifyOnValidationError; }
set { _binding.NotifyOnValidationError = value; }
}
public IValueConverter Converter
{
get { return _binding.Converter; }
set { _binding.Converter = value; }
}
public object ConverterParameter
{
get { return _binding.ConverterParameter; }
set { _binding.ConverterParameter = value; }
}
public CultureInfo ConverterCulture
{
get { return _binding.ConverterCulture; }
set { _binding.ConverterCulture = value; }
}
public object Source
{
get { return _binding.Source; }
set { _binding.Source = value; }
}
public RelativeSource RelativeSource
{
get { return _binding.RelativeSource; }
set { _binding.RelativeSource = value; }
}
public string ElementName
{
get { return _binding.ElementName; }
set { _binding.ElementName = value; }
}
public bool IsAsync
{
get { return _binding.IsAsync; }
set { _binding.IsAsync = value; }
}
public object AsyncState
{
get { return _binding.AsyncState; }
set { _binding.AsyncState = value; }
}
public bool BindsDirectlyToSource
{
get { return _binding.BindsDirectlyToSource; }
set { _binding.BindsDirectlyToSource = value; }
}
public UpdateSourceExceptionFilterCallback UpdateSourceExceptionFilter
{
get { return _binding.UpdateSourceExceptionFilter; }
set { _binding.UpdateSourceExceptionFilter = value; }
}
}
}