0

I've built a simple login page and when invalid input is detected, a red border is drawn around the usercontrol. image of login view

Here is my layout code:

<UserControl x:Class="WPFTest.UI.Views.EmptyLayout"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFTest.UI.Views"
             xmlns:vm="clr-namespace:WPFTest.UI.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             d:DataContext="{d:DesignInstance Type=vm:EmptyLayoutViewModel}"
             Background="White"
             >
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" FontSize="20" FontWeight="Bold">Test Sales Estimator</TextBlock>
    <ContentControl Content="{Binding Layout}" Grid.Row="1">
        <ContentControl.Resources>
                <DataTemplate DataType="{x:Type vm:LoginViewModel}">
                    <local:LoginView/>
                </DataTemplate>
            </ContentControl.Resources>
    </ContentControl>
    </Grid>
</UserControl>

And here is the login view:

<UserControl
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFTest.UI.Views" xmlns:viewmodels="clr-namespace:WPFTest.UI.ViewModels"
             xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" x:Class="WPFTest.UI.Views.LoginView"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800"
             Background="White"
             d:DataContext="{d:DesignInstance Type={x:Type viewmodels:LoginViewModel}}"
             Margin="20 0 0 0"
             Padding="10"
             >   
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Row="2" Margin="0 50 0 0">
            <TextBlock Text="Welcome" FontSize="17" Grid.Row="1" Margin="0 0 0 20" Height="50"/>
            <StackPanel>
                <TextBlock Text="Username" />
                <TextBox Text="{Binding Username}"/>
            </StackPanel>

            <StackPanel Grid.Row="2" Margin="0 10 0 0">
                <TextBlock Text="Password"  />
                <PasswordBox x:Name="Password" PasswordChanged="PasswordBox_PasswordChanged" >
                </PasswordBox>
            </StackPanel>
            <Button
            Grid.Row="2"
            Margin="0 20 0 0"
            Padding="5 2"
            HorizontalAlignment="Left"
            Command="{Binding HandleLoginCommand}"
            IsEnabled="{Binding CanLogin}"
            Content="Login">

            </Button>
        </StackPanel>
    </Grid>
</UserControl>

I have tried to override the border with the following template:

    <Style TargetType="views:LoginView">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="BorderBrush" Value="Blue"/>
                <Setter Property="BorderThickness" Value="1"/>
            </Trigger>
        </Style.Triggers>
    </Style>

But the border remains red. I've also tried changing the target on the template to things like UserControl, and ContentControl. I've also tried setting the Validation.ErrorTemplate attribute to {x:Null} on both the UserControl and on the element inside the layout usercontrol.

For the LoginViewModel, I am using the CommunityToolkit.Mvvm's ObservableValidator as my base class, so it handles the validation logic and here is my Username property.

 private string _username;
        [Required]
        [MinLength(4)]
        public string Username
        {
            get { return _username; }
            set { 
                SetProperty(ref _username, value, true);
                OnPropertyChanged(nameof(HandleLoginCommand));
            }
        }
George Fabish
  • 409
  • 2
  • 14

2 Answers2

2

The border is from your contentcontrol.

Set Validation.ErrorTemplate="{x:Null}" on that.

You can just use a contentpresenter.

    <ContentPresenter Content="{Binding Layout}"  Grid.Row="1"
                      Validation.ErrorTemplate="{x:Null}">
        <ContentPresenter.Resources>
            <DataTemplate DataType="{x:Type local:LoginViewModel}">
                <local:LoginView/>
            </DataTemplate>
        </ContentPresenter.Resources>
    </ContentPresenter>

I have a simplified layout to explore this, but the outer red border does not appear when I make that change.

enter image description here

Andy
  • 11,864
  • 2
  • 17
  • 20
  • I swear I tried this combo, but I guess not! Thanks! Also, I don't have much experience with WPF, would you suggest using a ContentPresenter vs ContentControl for my layout implementation? – George Fabish Feb 14 '23 at 16:13
  • Contentpresenter is slightly lighter and you can take satisfaction in a few bytes saved. – Andy Feb 14 '23 at 16:14
0

The validation decoration does not use the control's Border(Thcikness/Brush). It is instead a separate Visual that is drawn in a separate AdornerLayer. To modify its looks, you should pass a dedicated template for the ErrorTemplate like this: (example for TextBox)

<Style TargetType="TextBox">
  <Setter Property="Validation.ErrorTemplate">
    <Setter.Value>
      <ControlTemplate>
        <Grid>
          <Border BorderBrush="Yellow" BorderThickness="3">
            <AdornedElementPlaceholder x:Name="AdornedElementPlaceholder" />
          </Border>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

To actually remove the border, try setting Validation.ErrorTemplate to {x:Null}.

zaphod-ii
  • 424
  • 3
  • 11
  • Placing this inside `UserControl.Style` of my LoginView still does not remove or change the red border. As mentioned in my question, I have also attempted to set the Validation.ErrorTemplate to null, but that hasn't removed the border either. – George Fabish Feb 14 '23 at 15:15
  • I say you mentioning setting Validation.Error to null: "... I've also tried setting the Validation.Error attribute to {x:Null}...", so I decided that you tried to negate the error itself, not the visual template for its display. Maybe you meant Validation.ErrorTemplate there and I misundersstood you. – zaphod-ii Feb 14 '23 at 15:34
  • You're right! My mistake, I will update. – George Fabish Feb 14 '23 at 15:36