4

在我的规范示例中,我有两个选项卡,第一个带有按钮,第二个带有绑定到验证规则的文本框。单击按钮时会发生一个操作,该操作应导致验证失败,因此会触发 Validation.Error 事件。但是,该事件只会在我单击第二个选项卡时触发。

这对我来说如此重要的原因是我有一个跨多个选项卡发生复杂验证的表单,我想突出显示那些包含错误的选项卡 - 我特别想在表单首次加载时显示错误。

我已经使用了一种技术来强制在表单加载时触发验证,但我只是不知道为什么当表单加载时它不会在单击按钮时触发。

我的测试用例的 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; }
        }
    }
}
4

0 回答 0