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;
}
}
}