Intersoft ClientUI Documentation
Data Binding Overview

Data binding provides a simple and consistent way for applications to present and interact with data. Elements can be bound to data from a variety of data sources in the form of common language runtime (CLR) objects and XML. ContentControls such as UXButton and ItemsControls such as UXListBox have built-in functionality to enable flexible styling of single data items or collections of data items.

This topic contains the following sections.

Connecting User Interface Elements With Data

Every binding must specify a source and a target. The following illustration shows the basic concepts of a binding.

 

The binding engine gets information from the Binding object about the following:

The following example shows how to bind Image and Content of a GlassLabel to a value using data binding. The binding source is property of the MainPageViewModel class.

Model
Copy Code
using System.ComponentModel;

namespace ClientUI.Samples.Models
{
    public class Contact: INotifyPropertyChanged
    {
        private string _name;
        private string _image;

        public string Name
        {
            get { return this._name; }
            set
            {
                if (this._name != value)
                {
                    this._name = value;
                    this.OnPropertyChanged("Name");
                }
            }
        }

        public string Image
        {
            get { return this._image; }
            set
            {
                if (this._image != value)
                {
                    this._image = value;
                    this.OnPropertyChanged("Image");
                }
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
View Model
Copy Code
using ClientUI.Samples.Models;
using System.ComponentModel;

namespace ClientUI.Samples.ViewModels
{
    public class MainPageViewModel: INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            this.Contact = new Contact() { Image = "contact1.jpg", Name = "Vynna Lawrence" };
        }

        private Contact _contact;

        public Contact Contact
        {
            get { return this._contact; }
            set
            {
                if (this._contact != value)
                {
                    this._contact = value;
                    this.OnPropertyChanged("Contact");
                }
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
View
Copy Code
<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"    
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
    xmlns:vm="clr-namespace:ClientUI.Samples.ViewModels"
    mc:Ignorable="d"
        x:Class="ClientUI.Samples.MainPage" Width="800" Height="600">
    <UserControl.DataContext>
        <vm:MainPageViewModel/>
    </UserControl.DataContext>
    <Grid x:Name="LayoutRoot" Background="White">
        <Intersoft:GlassLabel HorizontalAlignment="Center" VerticalAlignment="Center" ContentType="ContentAndImage" 
                              ImageWidth="48" ImageHeight="48" ImageMargin="4" FontSize="16"
                              Content="{Binding Contact.Name}" ImageSource="{Binding Contact.Image}"/>
    </Grid>
</UserControl>  

This example is using MVVM pattern that utilize the binding concept. To learn more about MVVM see MVVM Pattern Overview.

The binding is created in XAML using the {Binding ...} syntax, the source is set by setting the DataContext property. In this sample the data context is set to UserControl.

Data context is inherited. If you set the data context on a parent element, all its children will use the same data context. A child element can override this behavior by setting the Source property on its binding object or by setting its DataContext which will then apply to all its children.

You can also use the ElementName property to specify the binding source. The ElementName property is useful when you are binding to other elements in your application such as when you are using a Slider to change the value of a TextBox.

XAML
Copy Code
<StackPanel HorizontalAlignment="Center" Height="22" Orientation="Horizontal" VerticalAlignment="Center">
        <Slider Width="150" Maximum="100" x:Name="Slider1"/>
        <Intersoft:UXTextBox Width="30" Text="{Binding Value, ElementName=Slider1}"/>             
</StackPanel>

You can bind a property of the source object by setting the Binding.Path property. The Path property supports a variety of syntax options for binding to nested properties, attached properties, string indexers.

Direction of Data Flow

Each binding has a Mode property, which determines how and when the data folows. There are three types of bindings as follows.

In order for automatic target updates to occur, the source object must implement INotifyPropertyChanged interface.

Change Notification

In order for changes to the souce object to propagate to the target, the source must implement the INotifyPropertyChanged interface.

INotifyPropertyChanged has the PropertyChanged event, which tells the binding engine that the source has changed so that the binding engine can update the target value.

In the following sample MainPageViewModel class implements the INotifyPropertyChanged  interface.

View Model
Copy Code
using ClientUI.Samples.Models;
using System.ComponentModel;

namespace ClientUI.Samples.ViewModels
{
    public class MainPageViewModel: INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            this.Contact = new Contact() { Image = "contact1.jpg", Name = "Vynna Lawrence" };
        }

        private Contact _contact;

        public Contact Contact
        {
            get { return this._contact; }
            set
            {
                if (this._contact != value)
                {
                    this._contact = value;
                    this.OnPropertyChanged("Contact");
                }
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

To get change notification for collections bound to an ItemsControl, implement INotifyCollectionChanged in addition to INotifyPropertyChanged. If you implement INotifyCollectionChanged, changes to the collection such as adding or removing object will propagate to the target. To get property change notification for objects in collection, the objects must implement INotifyPropertyChanged.

Updating the Data Source

In TwoWay bindings, changes to the target automatically update the source, except when binding to the Text property of a UXTextBox. In this case, the update occurs when the UXTextBox loses focus.

You can disable automatic source updates and update the source at times of your choosing. For example, you can do this to validate user input from multiple controls before you update the bound data sources.

To disable automatic source updates, set the UpdateSourceTrigger property to Explicit. This setting affects all bindings that use the same Binding object (for example, when using an inherited data context). You must update the source for each binding individually, however. To update a binding, first call the FrameworkElement.GetBindingExpression method of a target element, passing in the target DependencyProperty. You can then use the return value to call the BindingExpression.UpdateSource method. The following example code demonstrates this process.

XAML
Copy Code
<Intersoft:UXTextBox x:Name="textBox1" Text="{Binding Test, Mode=TwoWay, UpdateSourceTrigger=Explicit}" />
<Intersoft:UXButton Content="Update" Click="UXButton_Click" />
C#
Copy Code
public class TestData
{
    public String Test { get; set; }
}

TestData data;

public MainPage()
{
    InitializeComponent();
    data = new TestData { Test = "one" };
    textBox1.DataContext = data;
}

private void UXButton_Click(object sender, RoutedEventArgs e)
{
    BindingExpression expression = textBox1.GetBindingExpression(UXTextBox.TextProperty);
    MessageBox.Show("Before UpdateSource, Test = " + data.Test);
    expression.UpdateSource();
    MessageBox.Show("After UpdateSource, Test = " + data.Test);
}

Binding to Collections

A binding source object can be treated either as a single object whose properties contain data or as a collection of objects. For example, you might want to display a list of items, such contacts info. To do this, use an ItemsControl and repeat over a DataTemplate to display each item in a collection.

XAML
Copy Code
<UserControl.Resources>
        <DataTemplate x:Key="ItemTemplate1">
                <Intersoft:DockPanel FillChildMode="Custom">
                        <Image Source="{Binding Picture}" Height="64" Width="64" Intersoft:DockPanel.Dock="Left"/>
                        <Grid Intersoft:DockPanel.IsFillElement="True">
                                <StackPanel VerticalAlignment="Center" Margin="8">
                                        <TextBlock Text="{Binding ContactName}" />
                                        <TextBlock Text="{Binding EmailAddress}" />                               
                                </StackPanel>
                        </Grid>
                </Intersoft:DockPanel>
        </DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource SampleDataSource}}">
        <Intersoft:UXListBox HorizontalAlignment="Center" VerticalAlignment="Center" 
                                                        ItemTemplate="{StaticResource ItemTemplate1}" ItemsSource="{Binding Collection}"/>
</Grid>

You can enumerate over any collection that implements IEnumerable. If you want the target to update the ItemsSource when the collection changes, implement INotifyCollectionChanged. For more information on change notification, see the Change Notification section earlier in this topic.

Data Validation

Silverlight / WPF supports simple data validation in TwoWay bindings for target-to-source updates. It will reports a validation error whenever the Validation.Errors attached property of a binding contains errors.

Errors are added to this collection in the following cases:

The visual feedback will be provides for validation errors in the following cases:

To receive notification that a validation error has occurred or has been resolved, you must set the NotifyOnValidationError property to true on the binding object. This tells the binding engine to raise the BindingValidationError event when a validation error is added to or removed from the Validation.Errors collection. For example, you can handle the error event to log the error or provide additional visual feedback.

The following example shows how to provide custom binding validation using ValidatesOnExceptions.

View Model
Copy Code
using ClientUI.Samples.Models;
using System.ComponentModel;
using System;

namespace ClientUI.Samples.ViewModels
{
    public class MainPageViewModel: INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            
        }

        private double _value;

        public double Value
        {
            get { return this._value; }
            set
            {
                if (this._value != value)
                {
                    if (value < 0)
                        throw new Exception("Amount must be greater than zero.");

                    this._value = value;
                    this.OnPropertyChanged("Value");
                }
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
View
Copy Code
<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"    
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
    xmlns:vm="clr-namespace:ClientUI.Samples.ViewModels"
    mc:Ignorable="d"
        x:Class="ClientUI.Samples.MainPage" Width="800" Height="600">
        <Grid x:Name="LayoutRoot" Background="White">        
        <Grid.DataContext>
            <vm:MainPageViewModel/>
        </Grid.DataContext>
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Intersoft:UXTextBox Width="50" Margin="10">
                <Intersoft:UXTextBox.Text>
                    <Binding Mode="TwoWay" Path="Value" NotifyOnValidationError="true" ValidatesOnExceptions="true"/>
                </Intersoft:UXTextBox.Text>
            </Intersoft:UXTextBox>
            <Intersoft:UXButton Height="50" Width="150" Content="Click To Update Source"/>
        </StackPanel>
    </Grid>
</UserControl>   

This example is using MVVM pattern that utilize the binding concept. To learn more about MVVM, see MVVM Pattern Overview.

After the sample starts, type in letters instead of numbers to get an error caused by the type converter. Type in a negative number to get an error from the source object's set accessor. Type in a positive number to resolve the validation error. UXTextBox target-to-source updates occur only when the UXTextBox loses focus. The button is provided to change the focus. If you prefer, you can update the source manually in response to the button click, as described earlier in the Updating the Data Source section.

Data Conversion

Often you many need to display data in format that differs from how it is stored. For example:

You can create a converter for this kind of data binding by creating a class that inherits from IValueConverter. The following example shows how to create a ColorConverter that can display the color of a rectangle in its RGBA string representation and convert it back to RGBA value when the string is changed.

C#
Copy Code
using System;
using System.Windows.Data;
using System.Windows.Media;

namespace ClientUI.Samples.Converters
{
    public class ColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            SolidColorBrush colorBrush = (SolidColorBrush)value;

            string A = BitConverter.ToString(new byte[] { colorBrush.Color.A });
            string R = BitConverter.ToString(new byte[] { colorBrush.Color.R });
            string G = BitConverter.ToString(new byte[] { colorBrush.Color.G });
            string B = BitConverter.ToString(new byte[] { colorBrush.Color.B });

            return "#" + A + R + G + B;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string colorString = value as string;

            if (colorString.Length != 9)
            {
                throw new Exception("Invalid format");
            }
            else
            {
                byte A = System.Convert.ToByte(colorString.Substring(1, 2), 16);
                byte R = System.Convert.ToByte(colorString.Substring(3, 2), 16);
                byte G = System.Convert.ToByte(colorString.Substring(5, 2), 16);
                byte B = System.Convert.ToByte(colorString.Substring(7, 2), 16);

                SolidColorBrush colorBrush = new SolidColorBrush(Color.FromArgb(A, R, G, B));
                return colorBrush;
            }            
        }
    }
}
XAML
Copy Code
<UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Intersoft="http://intersoft.clientui.com/schemas"    
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
    xmlns:local="clr-namespace:ClientUI.Samples.Converters"
    mc:Ignorable="d"
        x:Class="ClientUI.Samples.MainPage" Width="800" Height="600">
    <UserControl.Resources>
        <local:ColorConverter x:Key="ColorConverter"></local:ColorConverter>
    </UserControl.Resources>
        <Grid x:Name="LayoutRoot" Background="White">        
                <StackPanel d:LayoutOverrides="Width" HorizontalAlignment="Center" VerticalAlignment="Center">
                        <Rectangle x:Name="Rectangle1" Fill="#FFF3B509" Height="24" Stroke="Black" Width="100"/>
                        <TextBox x:Name="TextBox1" TextWrapping="Wrap" Text="{Binding Fill, ElementName=Rectangle1, Mode=TwoWay, Converter={StaticResource ColorConverter}}"/>
                </StackPanel>
        </Grid>
</UserControl>     

 

Binding to Commands

Binding can also be used to bind commands to controls that implements ICommandSource. To learn more about commanding see Commanding Overview.

Using Advanced ClientUI Binding Framework

ClientUI Binding Framework provides a set of functionality to perform binding on some specific scenarios that are not currently supported in Silverlight platform. ClientUI also includes a cross-platform multi-binding capabilities which allows you to attach multiple data binding on a single dependency property. For more information, see Introduction to Multi Binding.

The following are several scenarios that you can achieve using the ClientUI Binding Framework.

Using Binding Descriptor

BindingDescriptor has three modes of binding that you can choose from, they are FindAncestor, FindName and Self. Each of this mode has different purpose and different settings.

FindAncestor

FindAncestor is used to bind the target with a specific ancestor element type defined in specific ancestor level range. This mode is commonly used when you know that a specific ancestor element type existed on certain level.

In this mode, you specify the AncestorType to determine the type of the target that will be bound and the AncestorLevel to determine how far it will look up for the ancestor with types specifed in AncestorType.

The default value of AncestorLevel is 1, so it will look at up one time and check whether the current ancestor match the type specified in AncestorType. If it matches, it will continue with the binding process.

The following example shows how to use FindAncestor mode to bind the elements inside ItemTemplate of a UXListBox to UXListBoxItem as their ancestor.

XAML
Copy Code
<Intersoft:UXListBox ItemsSource="{Binding Collection}" ImageMemberPath="Image" ItemContentType="ContentAndImage" 
                        ItemImageHeight="32" ItemImageWidth="32" HorizontalScrollBarVisibility="Disabled">
    <Intersoft:UXListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}"/>
                <StackPanel Orientation="Horizontal">
                    <Intersoft:BindingFramework.Binding>
                        <Intersoft:BindingDescriptor TargetProperty="Visibility" SourceProperty="IsSelected"
                                                                    Mode="FindAncestor" AncestorType="UXListBoxItem"
                                                                    Converter="{StaticResource VisibilityConverter}"/>
                    </Intersoft:BindingFramework.Binding>
                    <Intersoft:UXHyperlinkButton Content="Details" IsToggleButton="False" Foreground="Navy"/>
                    <Intersoft:UXHyperlinkButton Content="Order" IsToggleButton="False" Foreground="Navy" Margin="8,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </Intersoft:UXListBox.ItemTemplate>
</Intersoft:UXListBox>
C#
Copy Code
public class VisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool && targetType == typeof(Visibility))
        {
            if ((bool)value)
                return Visibility.Visible;
            else
                return Visibility.Collapsed;
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Visibility && targetType == typeof(bool))
        {
            if (((Visibility)value) == Visibility.Visible)
                return true;
            else
                return false;
        }

        return value;
    }
}

This sample bind the Visibility property of StackPanel to the IsSelected property of UXListBoxItem using FindAncestor. Notice that the BindingDescriptor also supports IValueConverter as discussed in previous section.

FindName

FindName is used to bind the target with an element with specific name. In this mode, you specify the ElementName that the target will be bound to.

The following example shows how to use FindName mode to bind the target with an element with the specific name specified in ElementName property.

XAML
Copy Code
<Grid Height="400" Width="550" x:Name="MainContainer" >

    <Intersoft:UXProgressBar Height="20" Maximum="700">
        <Intersoft:BindingFramework.Binding>
            <Intersoft:BindingDescriptor TargetProperty="Value" SourceProperty="Width"
                                            Mode="FindName" ElementName="MainContainer"/>
        </Intersoft:BindingFramework.Binding>
    </Intersoft:UXProgressBar>

</Grid>

This sample bind the Value property of UXProgressBar to MainContainer Width property using FindName.

Self

Self is used to bind the target within itself. You can bind one property with other property within the same element using this mode without needing to specify element name each time.

The following example shows how to use Self mode to bind Text property of UXTextBox to its BorderBrush.

XAML
Copy Code
<Intersoft:UXTextBox BorderThickness="4" Text="#FFFF0000" HorizontalAlignment="Center" VerticalAlignment="Center">
    <Intersoft:BindingFramework.Binding>
        <Intersoft:BindingDescriptor TargetProperty="BorderBrush" SourceProperty="Text" Mode="Self" Converter="{StaticResource ColorConverter}" />
    </Intersoft:BindingFramework.Binding>
</Intersoft:UXTextBox>

Using Property Binding

The XAML binding that uses {Binding ...} syntax cannot be defined in the Setter markup of Style because the Setter is not a dependency objeect. ClientUI Binding Framework provides a solution to address this limitation by introducing PropertyBinding.

PropertyBinding enables you overcome the Silverlight limitation so that you can define XAML data binding inside the Style. To understand how the property binding works, see the following example. 

Model
Copy Code
using System.ComponentModel;
using System.Windows.Media;

namespace ClientUI.Samples.Models
{
    public class Product : INotifyPropertyChanged
    {
        private string _name;
        private string _category;
        private SolidColorBrush _categoryBrush;
      
        public string Name
        {
            get { return this._name; }
            set
            {
                if (this._name!= value)
                {
                    this._name= value;
                    this.OnPropertyChanged("Name");
                }
            }
        }

        public string Category
        {
            get { return this._category; }
            set
            {
                if (this._category != value)
                {
                    this._category = value;

                    switch (value)
                    {
                        case "Red":
                            this.CategoryBrush = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
                            break;
                        case "Green":
                            this.CategoryBrush = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
                            break;
                        case "Blue":
                            this.CategoryBrush = new SolidColorBrush(Color.FromArgb(255, 0, 0, 255));
                            break;
                        default:
                            this.CategoryBrush = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));
                            break;
                    }
                    this.OnPropertyChanged("Category");
                }
            }
        }

        public SolidColorBrush CategoryBrush
        {
            get { return this._categoryBrush; }
            set
            {
                if (this._categoryBrush != value)
                {
                    this._categoryBrush = value;
                    this.OnPropertyChanged("CategoryBrush");
                }
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
View Model
Copy Code
using System.Collections.ObjectModel;
using System.ComponentModel;
using ClientUI.Samples.Models;

namespace ClientUI.Samples.ViewModels
{
    public class MainPageViewModel : INotifyPropertyChanged
    {
        public MainPageViewModel()
        {
            this.Products = new ObservableCollection<Product>();
            this.Products.Add(new Product() { Category = "Red", Name = "Product 1" });
            this.Products.Add(new Product() { Category = "Red", Name = "Product 2" });
            this.Products.Add(new Product() { Category = "Blue", Name = "Product 3" });
            this.Products.Add(new Product() { Category = "Blue", Name = "Product 4" });
            this.Products.Add(new Product() { Category = "Green", Name = "Product 5" });            
        }

        private ObservableCollection<Product> _products;

        public ObservableCollection<Product> Products
        {
            get { return this._products; }
            set
            {
                if (this._products != value)
                {
                    this._products = value;
                    this.OnPropertyChanged("Products");
                }
            }
        }

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
View
Copy Code
<Intersoft:UXListBox ItemsSource="{Binding Products}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100">                  
    <Intersoft:UXListBox.ItemContainerStyle>
        <Style TargetType="Intersoft:UXListBoxItem">
            <Setter Property="Intersoft:BindingFramework.PropertyBinding">
                <Setter.Value>
                    <Intersoft:PropertyBinding>
                        <Intersoft:PropertyBinding Property="BorderBrush" Binding="{Binding CategoryBrush}"/>
                        <Intersoft:PropertyBinding Property="Content" Binding="{Binding Name}"/>
                    </Intersoft:PropertyBinding>
                </Setter.Value>
            </Setter> 
            <Setter Property="BorderThickness" Value="1"></Setter>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
        </Style>
    </Intersoft:UXListBox.ItemContainerStyle>
</Intersoft:UXListBox>

This sample binds the UXListBox to a collection of products. Each product has a category that has different border coloring that bound to the BorderBrush of UXListBoxItem.

Clear Error on Text Input

ClearErrorOnTextInput is an attached property that you can used to enhance validation behavior. The standard validation behavior gives an error indication when the validation failed and stays visibile until a new validation takes place.

ClearErrorOnTextInput provides an enhanced behavior where you can clear the error indication immediately when you perform any text input.

The following example shows difference between input control that uses ClearErrorOnTextInput and input controls that does not use ClearErrorOnTextInput.

XAML
Copy Code
<Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
    <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60" 
                            Text="{Binding Path=Book.Price, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:c\}}"/>
</Intersoft:FieldLabel>

<Intersoft:FieldLabel Header="Price:" HeaderWidth="80" HorizontalHeaderAlignment="Right">
    <Intersoft:UXTextBox HorizontalAlignment="Center" Width="60" 
                            Text="{Binding Path=Book.Price, Mode=TwoWay, ValidatesOnDataErrors=True, ValidatesOnExceptions=True, StringFormat=\{0:c\}}"
                            Intersoft:DataBinding.ClearErrorOnTextInput="True"/>
</Intersoft:FieldLabel>
See Also