1

I am creating a login page in UWP using MVVM. When an incorrect password is put in I want the border of the PasswordBox to be changed to red to indicate it is incorrect.

I bound a SolidColorBrush variable to the Border and Background.

        private SolidColorBrush _validationColorBorder;
        public SolidColorBrush ValidationColorBorder
        {
            get{ return _validationColorBorder; }
            set
            {
                _validationColorBorder = value;
                RaisePropertyChanged();
            }
        }

        private SolidColorBrush _validationColorBackground;
        public SolidColorBrush ValidationColorBackground
        {
            get { return _validationColorBackground; }
            set
            {
                _validationColorBackground = value;
                RaisePropertyChanged();
            }
        }

in the ViewModel I set the colors to the validation Colors using this:

            ValidationColorBackground = (SolidColorBrush)Application.Current.Resources["TextBoxBackgroundThemeBrush"];
            ValidationColorBorder = (SolidColorBrush)Application.Current.Resources["TextBoxBorderThemeBrush"];

My issue is that after I set the password box background and border to these colors, I want to be able to set them back to the default colors afterwards.

How would I go about setting the colors back to the default colors of my application? And be able to do this in the MVVM format by setting my SolidColorBrush variables to these default colors?

Thanks for your help!

BWhelan
  • 378
  • 1
  • 5
  • 16
  • 1
    Relating to the colors; I think this should be fuly handled in the XAML. – Stefan Oct 21 '19 at 18:32
  • @Stefan How would I be able to handle the validation in just XAML, and reset to default colors? Or, do you mean the code-behind too? – BWhelan Oct 21 '19 at 18:35
  • 1
    Well... The reset of the color could be a trigger. Perhaps on focus or a similar event (XAML only). The color, change to red, could be based on a bool in the ViewModel which says that the authorization has failed. That way your ViewModel is not polluted with colors, which is more in line with the MVVM paradigm. – Stefan Oct 21 '19 at 18:52
  • Okay, but triggers aren't supported in UWP. Would I have to do something more like this? https://stackoverflow.com/questions/31929071/trigger-element-xaml-is-not-supported-in-a-uwp-project – BWhelan Oct 21 '19 at 19:05
  • Hmmm... yes, It seem like it. I haven't done UWP that much, but it seems valid. You'll need to find a applicable "trigger" though. The benefits will be that you can define all your coloring (and other things, like messages) just from a single property in your ViewModel. – Stefan Oct 21 '19 at 19:20

2 Answers2

1

How to reset Background color to default in MVVM?

Please check PasswrodBox style. The default Background and Border color are TextControlBackground and TextControlBorderBrush. So you could get them before you set the custom color.

defaultBgColor = (SolidColorBrush)Application.Current.Resources["TextControlBackground"];
defaultBorderColor = (SolidColorBrush)Application.Current.Resources["TextControlBorderBrush"];

If you want to rollback,you just need to copy above value to your custom binding property. For more please refer the following.

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private SolidColorBrush defaultBgColor;
    private SolidColorBrush defaultBorderColor;

    public ViewModel()
    {
        defaultBgColor = (SolidColorBrush)Application.Current.Resources["TextControlBackground"];
        defaultBorderColor = (SolidColorBrush)Application.Current.Resources["TextControlBorderBrush"];

        ValidationColorBackground = (SolidColorBrush)Application.Current.Resources["TextBoxBackgroundThemeBrush"];
        ValidationColorBorder = (SolidColorBrush)Application.Current.Resources["TextBoxBorderThemeBrush"];
    }
    private SolidColorBrush _validationColorBorder;
    public SolidColorBrush ValidationColorBorder
    {
        get { return _validationColorBorder; }
        set
        {
            _validationColorBorder = value;
            RaisePropertyChanged();
        }
    }

    private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private SolidColorBrush _validationColorBackground;
    public SolidColorBrush ValidationColorBackground
    {
        get { return _validationColorBackground; }
        set
        {
            _validationColorBackground = value;
            RaisePropertyChanged();
        }
    }

    public ICommand BtnClickCommand
    {
        get
        {
            return new RelayCommand(() =>
            {
                ValidationColorBackground = defaultBgColor;
                ValidationColorBorder = defaultBorderColor;
            });
        }
    }

}
Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
1

you could use Bevaviours to accomlpish this. You would need a property for Errors to bind to.

You would also need to create some Styles

See an example (=> taken from Prism)

using Microsoft.Xaml.Interactivity;
using Prism.Windows.Validation;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.UI.Xaml;

namespace ams.TaskmanagerClient.Behaviors
{
   Public Class HighlightFormFieldOnErrors : Behavior<FrameworkElement>
    {
        Public ReadOnlyCollection<String> PropertyErrors
        {
            Get { return (ReadOnlyCollection<String>)GetValue(PropertyErrorsProperty); }
            Set { SetValue(PropertyErrorsProperty, value); }
        }

        Public String HighlightStyleName
        {
            Get { return (String)GetValue(HighlightStyleNameProperty); }
            Set { SetValue(HighlightStyleNameProperty, value); }
        }

        Public String OriginalStyleName
        {
            Get { return (String)GetValue(OriginalStyleNameProperty); }
            Set { SetValue(OriginalStyleNameProperty, value); }
        }

        Public static DependencyProperty PropertyErrorsProperty =
            DependencyProperty.RegisterAttached("PropertyErrors", typeof(ReadOnlyCollection<String>), typeof(HighlightFormFieldOnErrors), New   r   opertyMetadata(BindableValidator.EmptyErrorsCollection, OnPropertyErrorsChanged));

        // The default For this Property only applies To TextBox controls. 
        Public static DependencyProperty HighlightStyleNameProperty =
            DependencyProperty.RegisterAttached("HighlightStyleName", typeof(String), typeof(HighlightFormFieldOnErrors), New   r op ert yMetadata("HighlightTextBoxStyle"));

        // The default For this Property only applies To TextBox controls. 
        protected static DependencyProperty OriginalStyleNameProperty =
            DependencyProperty.RegisterAttached("OriginalStyleName", typeof(Style), typeof(HighlightFormFieldOnErrors), New   r op ert yMetadata("BaseTextBoxStyle"));

        Private static void OnPropertyErrorsChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
        {
            If (args == Null || args.NewValue == Null)
            {
                return;
            }

            var control = ((Behavior<FrameworkElement>)d).AssociatedObject;
            var propertyErrors = (ReadOnlyCollection<String>)args.NewValue;

            Style style = (propertyErrors.Any()) ?
                (Style)Application.Current.Resources[((HighlightFormFieldOnErrors)d).HighlightStyleName] :
                (Style)Application.Current.Resources[((HighlightFormFieldOnErrors)d).OriginalStyleName];

            control.Style = style;
        }

        protected override void OnAttached()
        {
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
        }
    }
}


<Page
    x:Class="ams.TaskmanagerClient.Views.SettingsPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:helper="using:ams.TaskmanagerClient.Helpers"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Style="{StaticResource PageStyle}"
    xmlns:prismMvvm="using:Prism.Windows.Mvvm"
    xmlns:vm="using:ams.TaskmanagerClient.ViewModels"
    xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
    xmlns:helpers="using:ams.TaskmanagerClient.Helpers"
    xmlns:behaviors="using:ams.TaskmanagerClient.Behaviors"      
    prismMvvm:ViewModelLocator.AutoWireViewModel="True" 
    xmlns:xaml="using:Windows.UI.Xaml"
    mc:Ignorable="d">
    <Page.Resources>
        <helper:EnumToBooleanConverter x:Key="EnumToBooleanConverter" EnumType="ElementTheme" />
    </Page.Resources>

    <Grid>
      <PasswordBox x:Name="ClientSecretPasswordBox" 
                   x:Uid="ClientSecretPasswordBox" 
                   AutomationProperties.AutomationId="ClientSecretPasswordBox" 
                   AutomationProperties.IsRequiredForForm="True" 
                   Password="{Binding NewClient.ClientSecret, Mode=TwoWay}"
                   IsTabStop="True">
          <i:Interaction.Behaviors>
              <behaviors:HighlightFormFieldOnErrors OriginalStyleName="BasePasswordBoxStyle"
                                                    HighlightStyleName="HighlightPasswordBoxStyle"
                                                    PropertyErrors="{Binding NewClient.Errors[ClientSecret], Mode=OneWay}" />
          </i:Interaction.Behaviors>
      </PasswordBox>
    </Grid>
</Page>
thezapper
  • 486
  • 4
  • 13