为什么我的ConvertBack没有被调用,WPF Converter&有效性规则?

时间:2011-02-14 08:41:42

标签: c# wpf binding

我正在尝试绑定一个文本框,可以验证用','或';'分隔的电子邮件地址。目标是在页面上有一个复选框,一个文本框和一个按钮。如果勾选了复选框,那么用户必须输入一个有效的电子邮件地址,否则必须禁用该按钮。如果没有点击checdkbox,则必须启用该按钮。我正在用这个按钮绕圈,你能帮忙吗?

请在下面找到我的ViewModel结构:

public class EmailValidatorViewModel : DependencyObject
    {
        public EmailValidatorViewModel()
        {
            OnOkCommand = new DelegateCommand<object>(vm => OnOk(), vm => CanEnable());
            OtherRecipients = new List<string>();
        }

        private bool CanEnable()
        {
            return !IsChecked || HasOtherRecipients() ;
        }

        public static readonly DependencyProperty OtherRecipientsProperty =
            DependencyProperty.Register("OtherRecipients", typeof(List<string>), typeof(EmailValidatorViewModel));


        public List<string> OtherRecipients
        {
            get { return (List<string>)GetValue(OtherRecipientsProperty); }

            set
            {
                SetValue(OtherRecipientsProperty, value);
            }
        }


        public bool IsChecked { get; set; }

        public void OnOk()
        {
            var count = OtherRecipients.Count;
        }

        public bool HasOtherRecipients()
        {
            return OtherRecipients.Count != 0;
        }

        public DelegateCommand<object> OnOkCommand { get; set; }

    }

以下是我的XAML页面:

<Window x:Class="EMailValidator.EMailValidatorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:EMailValidator="clr-namespace:EMailValidator" Title="Window1" Height="300" Width="300">
    <Window.Resources>                   
        <Style x:Key="ToolTipBound" TargetType="TextBox">
            <Setter Property="Foreground" Value="#333333" />
            <Setter Property="MaxLength" Value="40" />
            <Setter Property="Width" Value="392" />
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
                        Path=(Validation.Errors)[0].ErrorContent}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Text" Value=""/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <EMailValidator:ListToStringConverter x:Key="ListToStringConverter" />
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"></RowDefinition>
            <RowDefinition Height="20"></RowDefinition>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <CheckBox Margin="15,0,0,0" x:Name="OthersCheckbox" Grid.Row="2" Grid.Column="0" Unchecked="OnOthersCheckboxUnChecked" IsChecked="{Binding Path=IsChecked}">Others</CheckBox>
        <TextBox Margin="5,0,5,0" x:Name="OtherRecipientsTextBox" Grid.Row="2" Grid.Column="1" IsEnabled="{Binding ElementName=OthersCheckbox, Path=IsChecked}" Style="{StaticResource ToolTipBound}">
            <TextBox.Text>
                <Binding  Path="OtherRecipients" Mode="TwoWay" Converter="{StaticResource ListToStringConverter}" NotifyOnSourceUpdated="True">
                    <Binding.ValidationRules>
                        <EMailValidator:EmailValidationRule/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>

        </TextBox>
        <Button x:Name="OkButton" Grid.Row="3" Grid.Column="0" Command="{Binding OnOkCommand}">Ok</Button>
    </Grid>
</Window>

我也在我的xaml页面的构造函数中设置我的datacontext如下所示。

 public EMailValidatorWindow()
        {
            InitializeComponent();

            DataContext = new EmailValidatorViewModel();
        }

这是我的电子邮件验证器:

    public class EmailValidationRule:ValidationRule
        {
            private const string EmailRegEx = @"\b[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}\b";

            private readonly Regex regEx = new Regex(EmailRegEx,RegexOptions.IgnoreCase);

            public override ValidationResult Validate(object value, CultureInfo cultureInfo)
            {
                var inputAddresses = value as string;

                if(inputAddresses == null)
                    return new ValidationResult(false,"An unspecified error occured while validating the input.Are you sure that you have entered a valid EMail address?");

                var list = inputAddresses.Split(new[] {';',','});

                var failures = list.Where(item => !regEx.Match(item).Success);

               if(failures.Count() <= 0)
                   return new ValidationResult(true,null);

                var getInvalidAddresses = string.Join(",", failures.ToArray());

                return new ValidationResult(false,"The following E-mail addresses are not valid:"+getInvalidAddresses+". Are you sure that you have entered a valid address seperated by a semi-colon(;)?.");
            }

...and my converter:

 public class ListToStringConverter:IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {

            var input = value as List<string>;

            if (input.Count == 0)
                return string.Empty;

            var output = string.Join(";", input.ToArray());

            return output;

        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var input = value as string;

            if (string.IsNullOrEmpty(input))
                return new List<string>();

            var list = input.Split(new[] { ';' });

            return list;
        }
    }

1 个答案:

答案 0 :(得分:4)

尝试在文本框绑定中将UpdateSourceTrigger设置为“PropertyChanged”。

<Binding UpdateSourceTrigger="PropertyChanged"  Path="OtherRecipients" Mode="TwoWay" Converter="{StaticResource ListToStringConverter}" NotifyOnSourceUpdated="True">