UWP Textbox Validation for any special characters

Indudhar Gowda 426 Reputation points
2020-06-18T13:14:07.967+00:00

UWP Textbox Validation ...

Need a simple Example for UWP Textbox Validation if any special characters entered.

10158-2.png

I dont want to Use any third party dll's nor nugget package..

Universal Windows Platform (UWP)
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,311 Reputation points
    2020-06-20T20:09:20.07+00:00

    Hi, see code in C#:

    <Page
        x:Class="App01.Page01"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App01"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
      <Page.DataContext>
        <local:ViewModel/>
      </Page.DataContext>
      <StackPanel>
        <Border BorderBrush="Green" BorderThickness="3" Margin="5">
          <StackPanel>
            <TextBlock Text="Input Value Name"/>
            <TextBox Text="{Binding View.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            <TextBlock Text="Input Value Age"/>
            <TextBox Text="{Binding View.Age, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
          </StackPanel>
        </Border>
        <Border BorderBrush="LightGreen" BorderThickness="3" Margin="5">
          <StackPanel>
            <TextBlock Text="UserControl examinates IDataError Name"/>
            <local:Page01UC1 DataObject="{Binding View}" PropertyName="Name"/>
            <TextBlock Text="UserControl examinates IDataError Age"/>
            <local:Page01UC1 DataObject="{Binding View}" PropertyName="Age"/>
          </StackPanel>
        </Border>
      </StackPanel>
    </Page>
    

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Runtime.CompilerServices;
    using Windows.UI.Xaml.Controls;
    
    namespace App01
    {
      public class ViewModel
      {
        public Data View { get; } = new Data();
      }
    
      public class Data : IDataErrorInfo, INotifyPropertyChanged
      {
    
        private string _name = string.Empty;
        public string Name
        {
          get => this._name;
          set
          {
            this._name = value;
            errorMessages[nameof(Name)] = this[nameof(Name)];
            OnPropertyChanged();
          }
        }
    
        private int _age = 0;
        private string _ageString = null;
        public object Age
        {
          get => this._age.ToString();
          set
          {
            if (value == null) this._ageString = "?";
            else
            {
              this._ageString = value.ToString();
              int.TryParse(value.ToString(), out this._age);
              errorMessages[nameof(Age)] = this[nameof(Age)];
              OnPropertyChanged();
            }
          }
        }
    
        private readonly Dictionary<String, String> errorMessages = new Dictionary<String, String>();
    
        public string Error
        {
          get
          {
            var result = string.Empty;
            foreach (KeyValuePair< String, String> em in errorMessages)
              if (!string.IsNullOrEmpty(em.Value))
                result += (String.IsNullOrEmpty(result)) ? em.Value : Environment.NewLine + em.Value;
            return result;
          }
        }
    
        public string this[string columnName]
        {
          get
          {
            var result = string.Empty;
            switch (columnName)
            {
              case "Name":
                if (String.IsNullOrEmpty(Name)) result = "Name may not be null or empty";
                break;
              case "Age":
                if (String.IsNullOrEmpty(this._ageString)) result = "Age may not be null or empty";
                else if (this._age < 18 || this._age > 65) result = "Age must be beetween 18 an 65";
                break;
            }
            return result;
          }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        internal void OnPropertyChanged([CallerMemberName] string propName = "") =>
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
      }
    }
    

    <UserControl
        x:Class="App01.Page01UC1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App01"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
      <Grid>
        <Border x:Name="border1" BorderBrush="Red" BorderThickness="3" Margin="0 0 0 10"/>
        <TextBox x:Name="tbox" Margin="2 2 2 12"/>
        <Border x:Name="border2" Background="Yellow" Margin="4 0 4 0" VerticalAlignment="Bottom">
          <TextBlock x:Name="tblock" />
        </Border>
      </Grid>
    </UserControl>
    

    using System;
    using System.ComponentModel;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    
    // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
    
    namespace App01
    {
      public sealed partial class Page01UC1 : UserControl
      {
        public Page01UC1()
        {
          this.InitializeComponent();
        }
    
        public static readonly DependencyProperty DataObjectProperty =
        DependencyProperty.RegisterAttached("DataObject", typeof(object),
                                            typeof(Page01UC1), new PropertyMetadata(null, PropChanged));
    
        public static object GetDataObject(DependencyObject obj) => obj.GetValue(DataObjectProperty);
        public static void SetDataObject(DependencyObject obj, object value) => obj.SetValue(DataObjectProperty, value);
    
        public static readonly DependencyProperty PropertyNameProperty =
        DependencyProperty.RegisterAttached("PropertyName", typeof(String),
                                            typeof(Page01UC1), new PropertyMetadata(string.Empty, PropChanged));
    
        public static string GetPropertyName(DependencyObject obj) => obj.GetValue(PropertyNameProperty).ToString();
    
        public static void SetPropertyName(DependencyObject obj, string value) => obj.SetValue(PropertyNameProperty, value);
    
        public string PropertyName { get; set; }
    
        private static void PropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          var uc = d as Page01UC1;
          var data = GetDataObject(d) as INotifyPropertyChanged;
          var name = GetPropertyName(d);
          if (uc == null || data == null || name == null) return;
          uc.PropertyName = name;
          data.PropertyChanged += uc.Data_PropertyChanged;
          uc.Data_PropertyChanged(data, null);
        }
        private void Data_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
          var t = sender.GetType();
          var pi = t.GetProperty(PropertyName);
          this.tbox.Text = pi.GetValue(sender).ToString();
          pi = t.GetProperty("Item");
          this.tblock.Text = pi.GetValue(sender, new object[] { PropertyName }).ToString();
          this.border1.Visibility = (String.IsNullOrEmpty(this.tblock.Text) ? Visibility.Collapsed : Visibility.Visible);
          this.border2.Visibility = this.border1.Visibility;
        }
      }
    }
    
    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. Daniele 1,996 Reputation points
    2020-06-19T18:06:15.503+00:00

    You could define your XAML as below: I suggest to use another Border around the TextBox to highlight the error because TextBox.BorderBrush is used by visual states and have different colors when TextBox when takes focus, is disabled, when the mouse is over, ecc...

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Border x:Name="TextBoxBorder" Grid.Row="0" Grid.Column="0" BorderThickness="2">
            <TextBox TextChanged="TextBox_OnTextChanged" />
        </Border>
        <TextBlock Grid.Row="0" Grid.Column="1" x:Name="ErrorTextBlock"
                   Margin="16,0"
                   VerticalAlignment="Center" Visibility="Collapsed"/>
    </Grid>
    

    Here TextBox_OnTextChanged definition:

    private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
    {
        var specialChars = new []{'#', '%', '^'};
    
        var textBox = (TextBox) sender;
        string textBoxText = textBox.Text;
        char[] mistakes = specialChars.Where(c => textBoxText.Contains(c)).ToArray();
        if (textBoxText.Contains("#"))
        {
            TextBoxBorder.BorderBrush = new SolidColorBrush(Colors.Red);
            ErrorTextBlock.Text = $"Characters {string.Join(", ", mistakes)} not allowed!";
            ErrorTextBlock.Visibility = Visibility.Visible;
        }
        else
        {
            TextBoxBorder.BorderBrush = null;
            ErrorTextBlock.Visibility = Visibility.Collapsed;
        }
    }
    

  2. Peter Fleischer (former MVP) 19,311 Reputation points
    2020-06-20T07:36:28.567+00:00

    Hi, you can build your own UserControl to bind data object with IDataError like in following simple demo:

    <Page  
        x:Class="App1.Page01"  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
        xmlns:local="using:App1.App01"  
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
        mc:Ignorable="d"  
        Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">  
      <Page.DataContext>  
        <local:ViewModel/>  
      </Page.DataContext>  
      <StackPanel>  
        <Border BorderBrush="Green" BorderThickness="3" Margin="5">  
          <StackPanel>  
            <TextBlock Text="Input Value Name"/>  
            <TextBox Text="{Binding View.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>  
            <TextBlock Text="Input Value Age"/>  
            <TextBox Text="{Binding View.Age, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>  
          </StackPanel>  
        </Border>  
        <Border BorderBrush="LightGreen" BorderThickness="3" Margin="5">  
          <StackPanel>  
            <TextBlock Text="UserControl examinates IDataError Name"/>  
            <local:Page01UC1 DataObject="{Binding View}" PropertyName="Name"/>  
            <TextBlock Text="UserControl examinates IDataError Age"/>  
            <local:Page01UC1 DataObject="{Binding View}" PropertyName="Age"/>  
          </StackPanel>  
        </Border>  
      </StackPanel>  
    </Page>  
      
    

    -------------------------------------------------------

    Namespace App01  
      
      Public Class ViewModel  
        Public ReadOnly Property View As New Data  
      End Class  
      
      Public Class Data  
        Implements IDataErrorInfo, INotifyPropertyChanged  
      
        Private _name As String = String.Empty  
        Public Property Name As String  
          Get  
            Return Me._name  
          End Get  
          Set  
            Me._name = Value  
            errorMessages(NameOf(Name)) = Item(NameOf(Name))  
            OnPropertyChanged()  
          End Set  
        End Property  
      
        Private _age As Integer = 0  
        Private _ageString As String = Nothing  
        Public Property Age As Object  
          Get  
            Return Me._age.ToString()  
          End Get  
          Set(value As Object)  
            If value Is Nothing Then  
              Me._ageString = "?"  
      
            Else  
              Me._ageString = value.ToString()  
              Integer.TryParse(value.ToString(), Me._age)  
              errorMessages(NameOf(Age)) = Item(NameOf(Age))  
              OnPropertyChanged()  
            End If  
          End Set  
        End Property  
      
        Private ReadOnly errorMessages As Dictionary(Of String, String) = New Dictionary(Of String, String)  
      
        Private ReadOnly Property IDataErrorInfo_Error As String Implements IDataErrorInfo.Error  
          Get  
            Dim result = String.Empty  
            For Each em In errorMessages  
              If Not String.IsNullOrEmpty(em.Value) Then  
                result += If(String.IsNullOrEmpty(result), em.Value, Environment.NewLine + em.Value)  
              End If  
            Next  
            Return result  
          End Get  
        End Property  
      
        Default Public ReadOnly Property Item(columnName As String) As String Implements IDataErrorInfo.Item  
          Get  
            Dim result = String.Empty  
            Select Case columnName  
              Case "Name" : If (String.IsNullOrEmpty(Name)) Then result = "Name may not be null or empty"  
              Case "Age"  
                If (String.IsNullOrEmpty(Me._ageString)) Then  
                  result = "Age may not be null or empty"  
                ElseIf Me._age < 18 OrElse Me._age > 65 Then  
                  result = "Age must be beetween 18 an 65"  
                End If  
            End Select  
            Return result  
          End Get  
        End Property  
      
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged  
        Protected Sub OnPropertyChanged(<CallerMemberName> Optional propertyName As String = "")  
          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))  
        End Sub  
      
      End Class  
      
    End Namespace  
      
    

    -------------------------------------------------------------

    <UserControl  
        x:Class="App1.App01.Page01UC1"  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
        xmlns:local="using:App1.App01"  
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
        mc:Ignorable="d"  
        d:DesignHeight="300"  
        d:DesignWidth="400">  
      <Grid>  
        <Border x:Name="border1" BorderBrush="Red" BorderThickness="3" Margin="0 0 0 10"/>  
        <TextBox x:Name="tbox" Margin="2 2 2 12"/>  
        <Border x:Name="border2" Background="Yellow" Margin="4 0 4 0" VerticalAlignment="Bottom">  
          <TextBlock x:Name="tblock" />  
        </Border>  
      </Grid>  
      
    

    -------------------------------------------------

    Imports System.Reflection  
      
    Namespace App01  
      
      Public NotInheritable Class Page01UC1  
        Inherits UserControl  
      
        Public Shared ReadOnly DataObjectProperty As DependencyProperty =  
        DependencyProperty.RegisterAttached("DataObject", GetType(Object),  
                                            GetType(Page01UC1), New PropertyMetadata(Nothing, AddressOf PropChanged))  
      
        Public Shared Function GetDataObject(obj As DependencyObject) As Object  
          Return obj.GetValue(DataObjectProperty)  
        End Function  
      
        Public Shared Sub SetDataObject(obj As DependencyObject, value As Object)  
          obj.SetValue(DataObjectProperty, value)  
        End Sub  
      
        Public Shared ReadOnly PropertyNameProperty As DependencyProperty =  
        DependencyProperty.RegisterAttached("PropertyName", GetType(String),  
                                            GetType(Page01UC1), New PropertyMetadata(String.Empty, AddressOf PropChanged))  
      
        Public Shared Function GetPropertyName(obj As DependencyObject) As String  
          Return CType(obj.GetValue(PropertyNameProperty), String)  
        End Function  
      
        Public Shared Sub SetPropertyName(obj As DependencyObject, value As String)  
          obj.SetValue(PropertyNameProperty, value)  
        End Sub  
      
        Public Property PropertyName As String  
      
        Private Shared Sub PropChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)  
          Dim uc = TryCast(d, Page01UC1)  
          Dim data = TryCast(GetDataObject(d), INotifyPropertyChanged)  
          Dim name = GetPropertyName(d)  
          If uc Is Nothing OrElse data Is Nothing OrElse name Is Nothing Then Exit Sub  
          uc.PropertyName = name  
          AddHandler data.PropertyChanged, AddressOf uc.Data_PropertyChanged  
          uc.Data_PropertyChanged(data, Nothing)  
        End Sub  
      
        Private Sub Data_PropertyChanged(sender As Object, e As PropertyChangedEventArgs)  
          Dim t As Type = sender.GetType  
          Dim pi As PropertyInfo = t.GetProperty(PropertyName)  
          Me.tbox.Text = pi.GetValue(sender).ToString  
          pi = t.GetProperty("Item")  
          Me.tblock.Text = pi.GetValue(sender, New Object() {PropertyName}).ToString  
          Me.border1.Visibility = If(String.IsNullOrEmpty(Me.tblock.Text), Visibility.Collapsed, Visibility.Visible)  
          Me.border2.Visibility = Me.border1.Visibility  
        End Sub  
      
      End Class  
      
    End Namespace  
    

    10415-20-06-2020-09-35-30.gif