Dependency Property Initial Value

90 views Asked by At

So I have as simple Custom Control that validates input from the User against a Regular Expression. The control has a HasError Property that is default to true.

Custom Control....

public class InputValidation : Control
{
    public string RegEX
    {
        get { return (string)GetValue(RegEXProperty); }
        set { SetValue(RegEXProperty, value); }
    }

    public static readonly DependencyProperty RegEXProperty =
        DependencyProperty.Register("RegEX", typeof(string), typeof(InputValidation), new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnRegEXBindingChanged));

    private static void OnRegEXBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ValidateInput(d);
    }

    public bool HasError
    {
        get { return (bool)GetValue(HasErrorProperty); }
        set { SetValue(HasErrorProperty, value); }
    }

    public static readonly DependencyProperty HasErrorProperty =
        DependencyProperty.Register("HasError", typeof(bool), typeof(InputValidation), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnHasErrorBindingChanged));

    private static void OnHasErrorBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
    }

    public string ErrorMessage
    {
        get { return (string)GetValue(ErrorMessageProperty); }
        set { SetValue(ErrorMessageProperty, value); }
    }

    public static readonly DependencyProperty ErrorMessageProperty =
        DependencyProperty.Register("ErrorMessage", typeof(string), typeof(InputValidation), new FrameworkPropertyMetadata("Incorrect", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnErrorMessageBindingChanged));

    private static void OnErrorMessageBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
    }

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(string), typeof(InputValidation), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextBindingChanged));

    private static void OnTextBindingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ValidateInput(d);
    }

    private static void ValidateInput(DependencyObject d)
    {
            var uc = d as InputValidation;
            if (IsInputValidValid(uc.Text, uc.RegEX))
            {
                uc.HasError = false;
            }
            else
            {
                uc.HasError = true;
            }
       
    }

    public static bool IsInputValidValid(string text, string regEX)
    {
        if (string.IsNullOrEmpty(text) || string.IsNullOrEmpty(regEX))
            return false;

        var regex = new Regex(regEX, RegexOptions.IgnoreCase);
        return regex.IsMatch(text);
    }

    static InputValidation()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(InputValidation), new FrameworkPropertyMetadata(typeof(InputValidation)));
    }
}

Control Style

<Window.Resources>

    <ControlTemplate x:Key="ValidationTemplate" TargetType="{x:Type Controls:InputValidation}">
        <Border x:Name="border" BorderBrush="Transparent" BorderThickness="1" Margin="1 ">
            <TextBox ToolTip="{Binding ErrorMessage, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource TemplatedParent}}" Text="{Binding Text, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}" Margin="1"></TextBox>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="HasError" Value="true">
                <Setter Property="BorderBrush" TargetName="border" Value="Red"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>

    <Style x:Key="EmailValidation" TargetType="{x:Type Controls:InputValidation}">
        <Setter Property="RegEX" Value="^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,6}|[0-9]{1,3})(\]?)$"/>
        <Setter Property="ErrorMessage" Value="Please Enter a Valid Email Address"/>
        <Setter Property="Template" Value="{StaticResource ValidationTemplate}"/>
    </Style>

</Window.Resources>

Control XAML

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <Label Content="Email Address" Width="100"/>
        <Controls:InputValidation HasError="{Binding HasEmailError, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Style="{StaticResource EmailValidation}" x:Name="EmailAddress" Width="200" Height="25" BorderBrush="Black" BorderThickness="1" 
                             Text="{Binding EmailAddress, UpdateSourceTrigger=PropertyChanged}" d:Text="[email protected]"/>
    </StackPanel>

    <StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
        <Button Width="100" HorizontalAlignment="Center" Content="OK"
            Command="{Binding Path=OKCommand}">
        </Button>
    </StackPanel>
</StackPanel>

View Model

public class MainViewModel : BaseViewModel
{
    public RelayCommand OKCommand { get; set; }

    private string _EmailAddress;

    public string EmailAddress
    {
        get { return _EmailAddress; }
        set { _EmailAddress = value; OnPropertyChanged(); }
    }

    private bool _HasEmailError;

    public bool HasEmailError
    {
        get { return _HasEmailError; }
        set { _HasEmailError = value; OnPropertyChanged(); }
    }

    public MainViewModel()
    {
        //HasEmailError = true;

        OKCommand = new RelayCommand(OnOKCommand, CanOKCommand);
        this.PropertyChanged += MainViewModel_PropertyChanged;
    }

    private bool CanOKCommand()
    {
        return !HasEmailError;
    }

    private void OnOKCommand()
    {
    }

    private void MainViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
    {

        OKCommand.RaiseCanExecuteChanged();
    }
}

The issue that I have is that, despite setting the Default Value of the HasError DP to true, it's not reflecting that state in the UI or the VM.

What I am expecting when the application first runs is the OK button to be disabled and a Red Border around the Text Box. But that's not happening (Button is enabled and no Red Border).

If I uncomment the HasEmailError = true; line, it works fine. Am I missing something really simple?

0

There are 0 answers