Why does my ConvertBack not getting called, WPF Converter & ValidationRule?
I'm trying to bind a textbox which can validate email addresses split by ',' or ';'.The objective is to have a checkbox, a textbox and a button on the page.If the checkbox is checked, then the user has to enter a valid email address or else the button has to be disabled.If the checdkbox is not clicked then the button has to be enabled.I'm going round in circles with this one, could you please help?
Please find my ViewModel structure below:
public class EmailValidatorViewModel : DependencyObject
{
public EmailValidatorViewModel()
{
OnOkCommand = new DelegateCommand<object>(vm => OnOk(), vm => CanEnable());
OtherRecipients = new List<string>();
}
private bool CanE开发者_如何转开发nable()
{
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; }
}
Also below is my XAML page:
<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>
Also I do set my datacontext as below in the constructor of my xaml page.
public EMailValidatorWindow()
{
InitializeComponent();
DataContext = new EmailValidatorViewModel();
}
Here is my EMail Validator:
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;
}
}
Try setting the UpdateSourceTrigger to 'PropertyChanged' in your textbox binding.
<Binding UpdateSourceTrigger="PropertyChanged" Path="OtherRecipients" Mode="TwoWay" Converter="{StaticResource ListToStringConverter}" NotifyOnSourceUpdated="True">
精彩评论