Archive for the ‘Binding’ Category.

A SpinningImage control in WPF

In the past, I once wrote an article about WPF replacement options for an animated gif.

I have added an example project on GitHub: WpfSharp.Controls

Recently I needed to use this again, but I wanted a control that was more MVVM friendly. I also didn’t want to have to add a bunch of XAML every time I used it. This might sound crazy, but I wanted a reusable object. (Crazy right? 😉 Anyway, this led me to create a custom control that inherits from Image called SpinningImage.

So here is what I wanted. An Image with a simple bool dependency property that makes the image spin when true and stop spinning when false.

I used both XAML and csharp for this:

<Image x:Class="WpfSharp.UserControls.SpinningImage"
             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" 
             Name="ImageInstance"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             RenderTransformOrigin="0.5, 0.5" >
    <Image.Resources>
        <Storyboard x:Key="Spin360" Storyboard.TargetName="ImageInstance" Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)">
            <DoubleAnimation From="0" To="360" BeginTime="0:0:0" Duration="0:0:2" RepeatBehavior="Forever" />
        </Storyboard>
    </Image.Resources>
    <Image.RenderTransform>
        <RotateTransform Angle="0" />
    </Image.RenderTransform>
</Image>
using System.Windows;
using System.Windows.Media.Animation;

namespace WpfSharp.UserControls
{
    /// <summary>
    /// Interaction logic for SpinningImage.xaml
    /// </summary>
    public partial class SpinningImage
    {
        public SpinningImage()
        {
            InitializeComponent();
        }

        public Storyboard Spinner
        {
            get { return _Spinner ?? (_Spinner = (Storyboard)FindResource("Spin360")); }
        } private Storyboard _Spinner;

        public bool SpinnerState
        {
            get { return (bool)GetValue(SpinnerStateProperty); }
            set { SetValue(SpinnerStateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SpinnerState.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SpinnerStateProperty =
            DependencyProperty.Register("SpinnerState", typeof(bool), typeof(SpinningImage), new UIPropertyMetadata(false, OnSpinnerStatePropertyChanged));

        public static void OnSpinnerStatePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            var view = source as SpinningImage;
            if (view == null) return;
            if ((bool)e.NewValue)
                view.Spinner.Begin();
            else
                view.Spinner.Stop();
        }
    }
}

Now to use this in XAML, it is quite simple.

            <wpfsharp:SpinningImage Name="ImageGraySpinner" Source="/Images/GraySpinner.png" Height="128" Width="128" SpinnerState="{Binding Path=IsExecuting}"/>

Feel free to enhance it. It probably would be nice to enhance this and make dependency properties for Storyboard variables such as Duration. It might even be a good idea to move the StoryBoard to code and eliminate the XAML in the custom control. Either way, this control is easy to stick into a library and use.

Displaying Images from a folder with details in WPF

Today I decided to write how to display images from a folder with details using WPF.

What is my motivation? This StackOverflow post: 
http://stackoverflow.com/questions/13034911/create-control-instance-in-wpf

Here is my full example project: ImageList.zip

The first thing I did was create a new WPF Project in Visual Studio. After that I followed these steps.

  1. Created an Images folder in the project and added two images.
  2. Changed the images properties in Visual Studio to have a Build Action of Content and to only Copy if newer.
  3. Created an ImageDetails object.
  4. Created XAML for displaying the image using binding.
  5. Wrote code behind to load images from a folder, get the image details, and add them to a list. Note: I had to add a reference to System.Drawing to use System.Drawing.Image.

The Model.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ImageList.Model
{
    public class ImageDetails
    {
        /// <summary>
        /// A name for the image, not the file name.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// A description for the image.
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// Full path such as c:\path\to\image.png
        /// </summary>
        public string Path { get; set; }

        /// <summary>
        /// The image file name such as image.png
        /// </summary>
        public string FileName { get; set; }

        /// <summary>
        /// The file name extension: bmp, gif, jpg, png, tiff, etc...
        /// </summary>
        public string Extension { get; set; }
        
        /// <summary>
        /// The image height
        /// </summary>
        public int Height { get; set; }

        /// <summary>
        /// The image width.
        /// </summary>
        public int Width { get; set; }

        /// <summary>
        /// The file size of the image.
        /// </summary>
        public long Size { get; set; }
        
    }
}

The XAML. Basically it is an ItemsControl with an ItemsTemplate and all the complexity and binding is in the ItemsTemplate.

<Window x:Class="ImageList.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded_1">
    <Grid>
        <ItemsControl Name="ImageList" ItemsSource="{Binding ImageList}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderThickness="1" BorderBrush="#FFD0D1D7" Padding="5" Margin="10,10,0,0">
                        <StackPanel Orientation="Horizontal">
                            <!--image and dimensions-->
                            <Grid Width="88" Height="55">
                                <Image Source="{Binding Path}"/>
                                <TextBlock Background="#B2000000" Foreground="White" Height="16" TextAlignment="Center" VerticalAlignment="Bottom">
                                    <TextBlock.Text>
                                        <MultiBinding StringFormat="{}{0}x{1}">
                                            <Binding Path="Height"/>
                                            <Binding Path="Width"/>
                                        </MultiBinding>
                                    </TextBlock.Text>
                                </TextBlock>
                            </Grid>
                            <!--name, type and size-->
                            <StackPanel Orientation="Vertical" Margin="5,0,0,0" VerticalAlignment="Center">
                                <TextBlock Name="ImageName" Margin="1" Foreground="#FF787878" Text="{Binding FileName}"/>
                                <TextBlock Name="ImageType" Margin="1" Foreground="#FF787878">
                                    <TextBlock.Text>
                                        <MultiBinding StringFormat="Type: {0}">
                                            <Binding Path="Extension"/>
                                        </MultiBinding>
                                    </TextBlock.Text>
                                </TextBlock>
                                <TextBlock Name="ImageSize" Margin="1" Foreground="#FF787878">
                                    <TextBlock.Text>
                                        <MultiBinding StringFormat="Size: {0} Bytes">
                                            <Binding Path="Size"/>
                                        </MultiBinding>
                                    </TextBlock.Text>
                                </TextBlock>
                            </StackPanel>
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>
</Window>

The Code behind. Feel free to switch this to use MVVM if needed. I didn’t use MVVM only because this is an example only.

using ImageList.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ImageList
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded_1(object sender, RoutedEventArgs e)
        {
            string root = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
            string[] supportedExtensions = new[] { ".bmp", ".jpeg", ".jpg", ".png", ".tiff" };
            var files = Directory.GetFiles(Path.Combine(root, "Images"), "*.*").Where(s => supportedExtensions.Contains(Path.GetExtension(s).ToLower()));

            List<ImageDetails> images = new List<ImageDetails>();

            foreach (var file in files)
            {
                ImageDetails id = new ImageDetails()
                {
                    Path = file,
                    FileName = Path.GetFileName(file),
                    Extension = Path.GetExtension(file)
                };

                BitmapImage img = new BitmapImage();
                img.BeginInit();
                img.CacheOption = BitmapCacheOption.OnLoad;
                img.UriSource = new Uri(file, UriKind.Absolute);
                img.EndInit();
                id.Width = img.PixelWidth;
                id.Height = img.PixelHeight;

                // I couldn't find file size in BitmapImage
                FileInfo fi = new FileInfo(file);
                id.Size = fi.Length;
                images.Add(id);
            }

            ImageList.ItemsSource = images;
        }
    }
}

Creating an Interface for data binding in Views with WPF

Perhaps you have seen the same idea as me. A list of bound objects and an interface with a list of properties, have a lot in common. To start with, both are contracts. By adding Bindings in WPF, you are creating a contract that promises any code that uses the view that if such code has certain properties to bind to, the view will bind to them. Similarly an interface is a contract wherein an object that implements the interface is required to comply with the interface else a build error.

Look at the following UserControl view.

<UserControl x:Class="BindingsAsInterfaceExample.View.PeopleView"
             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"
             mc:Ignorable="d"
             d:DesignHeight="200"
             d:DesignWidth="300"
             >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <DataGrid ItemsSource="{Binding People}" Grid.Row="0" Grid.ColumnSpan="3" HeadersVisibility="Column" CanUserAddRows="False" />
        <Button Content="Add Person" Command="{Binding AddPersonCommand}" Grid.Row="1" Grid.Column="0" />
        <Button Content="Edit Person" Command="{Binding EditPersonCommand}" Grid.Row="1" Grid.Column="1" />
        <Button Content="Delete Person" Command="{Binding DeletePersonCommand}" Grid.Row="1" Grid.Column="2" />
    </Grid>
</UserControl>

There are four bindings in this view. It may be beneficial to make these bindings into a concrete contract using an interface.

public interface IPeopleViewBindings
{
    IList People { get; set; }
    ICommand AddPersonCommand { get; set; }
    ICommand EditPersonCommand { get; set; }
    ICommand DeletePersonCommand { get; set; }
}

Then when implementing the view model, have it implement the interface. Now if some binding value is missing, a compile time error occurs.

using System.Collections;
using System.Collections.Generic;
using System.Windows.Input;
using BindingsAsInterfaceExample.Interfaces;
using BindingsAsInterfaceExample.Model;
using MVVM;

namespace BindingsAsInterfaceExample.ViewModel
{
    class PeopleViewModel : ViewModelBase, IPeopleViewBindings
    {
        #region Properties
        public IList People
        {
            get { return _People ?? (_People = CreateSamplePeople()); }
            set { _People = value; }
        } private IList _People;

        public ICommand AddPersonCommand
        {
            get
            {
                return _AddPersonCommand ??
                    (_AddPersonCommand = new RelayCommand(f => AddPerson(), f => AddPersonCanExecute()));
            }
            set { _AddPersonCommand = value; }
        } private ICommand _AddPersonCommand;

        public ICommand EditPersonCommand
        {
            get
            {
                return _EditPersonCommand ??
                    (_EditPersonCommand = new RelayCommand(f => EditPerson(), f => EditPersonCanExecute()));
            }
            set { _EditPersonCommand = value; }
        } private ICommand _EditPersonCommand;

        public ICommand DeletePersonCommand
        {
            get
            {
                return _DeletePersonCommand ??
                    (_DeletePersonCommand = new RelayCommand(f => DeletePerson(), f => DeletePersonCanExecute()));
            }
            set { _DeletePersonCommand = value; }
        } private ICommand _DeletePersonCommand;
        #endregion

        #region Functions
        private IList CreateSamplePeople()
        {
            IList people = new List<Person>();

            people.Add(new Person() { FirstName = "John", MiddleName = "J.", LastName = "Johnson" });
            people.Add(new Person() { FirstName = "Mark", MiddleName = "M.", LastName = "Markson" });
            people.Add(new Person() { FirstName = "Thom", MiddleName = "T.", LastName = "Thompson" });

            return people;
        }

        private void AddPerson()
        {
            // ...
        }

        private bool AddPersonCanExecute()
        {
            return true;
        }

        private void EditPerson()
        {
            // ...
        }

        private bool EditPersonCanExecute()
        {
            return true;
        }

        private void DeletePerson()
        {
            // ...
        }

        private bool DeletePersonCanExecute()
        {
            return true;
        }
        #endregion
    }
}

This is solution is not without problems.

  1. Now when you add a binding to a view, you have to remember to add it to the interface as well, otherwise you are no better off.
  2. Interfaces don’t support private fields and a lot of the methods are private.

However, it is actually quite useful when creating an API that someone else is consuming. Users of the API documentation will be grateful for the interfaces.

MVVM and Drag and Drop Command Binding with an Attached Behavior

Drag and drop works quite well already with some UIElements, such as TextBox. However, you may want to using MVVM and binding to bind a command for dragging and dropping to a UIElement that doesn’t support drag and drop, such as a Grid or other container.

This can easily be done using an Attached Behavior. You may know what an Attached Property is and you may be wondering, what is the difference between an Attached Behavior and an Attached Property. An Attached Behavior is a type of an Attached Property that involves certain events, often user interaction events such a drag and drop.

Creating an Attached Behavior for use in WPF

So what is the basic recipe for creating an Attached Behavior.

  1. Use a public static class
  2. Add a static Dependency Property and and an associated PropertyChangedCallBack method (after testing, these can be private)
  3. Add a public method that is a static setter and getter (after testing the getter can be private)
  4. Add any static helper methods (usually these could be private)
  5. Add any additional code that is needed.

Handling Drag and Drop in WPF

If you are going to handle Drag and Drop in WPF, you need to make yourself acquainted with a particular static object called DataFormats (System.Windows.DataFormats, as there exists one in the Forms namespace too).   This object is going to help you. Microsoft says that the DataFormats class provides a set of predefined data format names that can be used to identify data formats available in the clipboard or drag-and-drop operations.[1] You should take a moment to read about this class if you are not familiar with it. IDataObject and DataObject (which implements IDataObject) are also important to know and you should read about those as well.

Determine which types of data your need to handle with Drag and Drop. For each data type you plan to handle, you should check if the drag and drop data is that type and if so, handle it. You have the option to handle this in the code behind or in the behavior.

Also, with UIElements in WPF, the drag events are separate from the drop events, so we really don’t need a DragBehavior or DragAndDropBehavior, instead we only need a DropBehavior.[2]  You should read about the drag and drop events and understand which one you need to add a behavior too. We are going to use the PreviewDrop event.

Writing a DropBehavior

Ok, now that we have gained the knowledge we need, lets write a DropBavior static class.

  1. Create a new class and call it DropBehavior.
  2. Make the class both public and static.
  3. Add a DependecyProperty called PreviewDropCommandProperty (Lines 13 – 26).
  4. Create the Setter and Getter functions. (Lines 28-57)
  5. Create the PropertyChangedCallBack method. (Lines 59-78)
using System.Windows.Input;
using System.Windows;

namespace MVVM
{
    /// <summary>
    /// This is an Attached Behavior and is intended for use with
    /// XAML objects to enable binding a drag and drop event to
    /// an ICommand.
    /// </summary>
    public static class DropBehavior
    {
        #region The dependecy Property
        /// <summary>
        /// The Dependency property. To allow for Binding, a dependency
        /// property must be used.
        /// </summary>
        private static readonly DependencyProperty PreviewDropCommandProperty =
                    DependencyProperty.RegisterAttached
                    (
                        "PreviewDropCommand",
                        typeof(ICommand),
                        typeof(DropBehavior),
                        new PropertyMetadata(PreviewDropCommandPropertyChangedCallBack)
                    );
        #endregion

        #region The getter and setter
        /// <summary>
        /// The setter. This sets the value of the PreviewDropCommandProperty
        /// Dependency Property. It is expected that you use this only in XAML
        ///
        /// This appears in XAML with the "Set" stripped off.
        /// XAML usage:
        ///
        /// <Grid mvvm:DropBehavior.PreviewDropCommand="{Binding DropCommand}" />
        ///
        /// </summary>
        /// <param name="inUIElement">A UIElement object. In XAML this is automatically passed
        /// in, so you don't have to enter anything in XAML.</param>
        /// <param name="inCommand">An object that implements ICommand.</param>
        public static void SetPreviewDropCommand(this UIElement inUIElement, ICommand inCommand)
        {
            inUIElement.SetValue(PreviewDropCommandProperty, inCommand);
        }

        /// <summary>
        /// Gets the PreviewDropCommand assigned to the PreviewDropCommandProperty
        /// DependencyProperty. As this is only needed by this class, it is private.
        /// </summary>
        /// <param name="inUIElement">A UIElement object.</param>
        /// <returns>An object that implements ICommand.</returns>
        private static ICommand GetPreviewDropCommand(UIElement inUIElement)
        {
            return (ICommand)inUIElement.GetValue(PreviewDropCommandProperty);
        }
        #endregion

        #region The PropertyChangedCallBack method
        /// <summary>
        /// The OnCommandChanged method. This event handles the initial binding and future
        /// binding changes to the bound ICommand
        /// </summary>
        /// <param name="inDependencyObject">A DependencyObject</param>
        /// <param name="inEventArgs">A DependencyPropertyChangedEventArgs object.</param>
        private static void PreviewDropCommandPropertyChangedCallBack(
            DependencyObject inDependencyObject, DependencyPropertyChangedEventArgs inEventArgs)
        {
            UIElement uiElement = inDependencyObject as UIElement;
            if (null == uiElement) return;

            uiElement.Drop += (sender, args) =>
            {
                GetPreviewDropCommand(uiElement).Execute(args.Data);
                args.Handled = true;
            };
        }
        #endregion
    }
}

Using the DropBehavior in XAML

Ok, now it is really easy to add this to a Grid or other UIElement that doesn’t already handle Drag and Drop. If you try to add this to a TextBlox, which already handles Drag and Drop, this even doesn’t fire.

Examples

You can add the DropBehavior to a UserControl

<UserControl x:Class="DropBehaviorExample.ExampleView"
             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:MVVM="clr-namespace:MVVM"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="400"
             AllowDrop="True"
             MVVM:DropBehavior.PreviewDropCommand="{Binding PreviewDropCommand}"
             >
    <Grid>
    </Grid>
</UserControl>

Or you can add the DropBehavior to a Grid.

<UserControl x:Class="DropBehaviorExample.ExampleView"
             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:MVVM="clr-namespace:MVVM"
             mc:Ignorable="d"
             d:DesignHeight="300"
             d:DesignWidth="400"
             AllowDrop="True"
             >
    <Grid MVVM:DropBehavior.PreviewDropCommand="{Binding PreviewDropCommand}">
    </Grid>
</UserControl>

And of course, you can put it on any UIElement that doesn’t already handle drag and drop.

Implementing the ICommand in the ViewModel

The following code is all you need in your ViewModel to bind the PreviewDropCommand.

        #region The RelayCommand that implements ICommand
        public ICommand PreviewDropCommand
        {
            get { return _PreviewDropCommand ?? (_PreviewDropCommand = new RelayCommand(HandlePreviewDrop)); }
            set
            {
                _PreviewDropCommand = value;
                NotifyPropertyChanged("PreviewDropCommand");
            }
        } private ICommand _PreviewDropCommand;

        #endregion

        #region The method encapsulated in the relay command
        private void HandlePreviewDrop(object inObject)
        {
            IDataObject ido = inObject as IDataObject;
            if (null == ido) return;

            // Get all the possible format
            string[] formats = ido.GetFormats();

            // Do what you need here based on the format passed in.
            // You will probably have a few options and you need to
            // decide an order of preference.
        }
        #endregion

Hope this helps you. I know when I first rounded up this information online, it was hard to understand because of lack of preparation information, so I made sure to provide that, and also lack of comments, so I made sure to provide that.

How to disable a Button on TextBox ValidationErrors in WPF

Lets say  you want to create a submittable form in WPF. You want to make sure the form is filled out with valid values and you want the Submit button to be disabled until the form is filled out with valid values. Of course, the error text should display on error only.

See the picture on the right.

This is quite simple. Here is a sample project that demonstrates this: WpfTextBoxValidation.zip

Accomplishing this is done by using a few different tools available:

  • ValidationRules
  • Binding and MultiBinding
  • Triggers and MultiDataTriggers

So the code is so simple, I am going to skip the step by step instructions for time reasons. However, the code is pretty self documenting as the object names are obvious and the UI objects are obvious, at least when viewed in the Designer.

<Window x:Class="WpfTextBoxValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfTextBoxValidation"
        Title="MainWindow" Height="350" Width="525">
    <Grid Name="MainGrid" Margin="10">
        <Grid.Resources>
            <Style TargetType="TextBox">
                <Setter Property="MaxWidth" Value="200" />
            </Style>
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="Auto" MinWidth="200" />
            <ColumnDefinition Width="237*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="129*" />
        </Grid.RowDefinitions>

        <!-- Labels -->
        <TextBlock Name="labelFirstName" Text="FirstName" Margin="5" />
        <TextBlock Name="labelLastName" Text="LastName" Grid.Row="1" Margin="5" />
        <TextBlock Text="Age" Grid.Row="2" Margin="5" />
        <TextBlock Text="Phone" Grid.Row="3" Margin="5" />

        <!-- TextBlocks -->
        <TextBox Name="TextBoxFirstName"  Grid.Column="1" Margin="5">
            <TextBox.Text>
                <Binding Path="FirstName" UpdateSourceTrigger="PropertyChanged" >
                    <Binding.ValidationRules>
                        <local:TextBoxNotEmptyValidationRule x:Name="FirstNameValidation" ValidatesOnTargetUpdated="True"
                                                             Message="You must enter a first name."/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBox Name="TextBoxLastName" Grid.Row="1" Grid.Column="1" Margin="5">
            <TextBox.Text>
                <Binding Path="LastName" UpdateSourceTrigger="PropertyChanged" >
                    <Binding.ValidationRules>
                        <local:TextBoxNotEmptyValidationRule x:Name="LastNameValidation" ValidatesOnTargetUpdated="True"
                                                             Message="You must enter a last name."/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBox Name="TextBoxAge" Grid.Row="2" Grid.Column="1" Margin="5">
            <TextBox.Text>
                <Binding Path="Age" UpdateSourceTrigger="PropertyChanged" >
                    <Binding.ValidationRules>
                        <local:OverThirteenValidationRule x:Name="AgeValidation" ValidatesOnTargetUpdated="True"/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>
        <TextBox Name="TextBoxPhone" Grid.Row="3" Grid.Column="1" Margin="5">
            <TextBox.Text>
                <Binding Path="Phone" UpdateSourceTrigger="PropertyChanged" >
                    <Binding.ValidationRules>
                        <local:TextBoxNotEmptyValidationRule x:Name="PhoneValidation" ValidatesOnTargetUpdated="True"
                                                             Message="You must enter a phone number."/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <!-- Validation List -->
        <StackPanel Grid.Row="4" Grid.ColumnSpan="2" Margin="5">
            <StackPanel.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="Foreground" Value="Red" />
                </Style>
                <local:ErrorCollectionToVisibility x:Key="ToVisibility" />
            </StackPanel.Resources>
            <TextBlock Visibility="{Binding ElementName=TextBoxFirstName, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">
                <TextBlock.Text>
                    <MultiBinding StringFormat="{}{0} - {1}">
                        <Binding ElementName="labelFirstName" Path="Text"/>
                        <Binding ElementName="TextBoxFirstName" Path="(Validation.Errors)[0].ErrorContent"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
            <TextBlock Visibility="{Binding ElementName=TextBoxLastName, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">>
                <TextBlock.Text>
                    <MultiBinding StringFormat="LastName - {0}">
                        <Binding ElementName="TextBoxLastName" Path="(Validation.Errors)[0].ErrorContent"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
            <TextBlock Visibility="{Binding ElementName=TextBoxAge, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">>
                <TextBlock.Text>
                    <MultiBinding StringFormat="Age - {0}">
                        <Binding ElementName="TextBoxAge" Path="(Validation.Errors)[0].ErrorContent"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
            <TextBlock Visibility="{Binding ElementName=TextBoxPhone, Path=(Validation.Errors), Converter={StaticResource ToVisibility}}">>
                <TextBlock.Text>
                    <MultiBinding StringFormat="Phone - {0}">
                        <Binding ElementName="TextBoxPhone" Path="(Validation.Errors)[0].ErrorContent"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
            <!--Text="{Binding ElementName=DirectoryBox, Path=(Validation.Errors)[0].ErrorContent}"-->
        </StackPanel>
        <Button Content="Submit" Grid.Column="1" Grid.Row="5" Margin="5" Padding="10,3,10,3" HorizontalAlignment="Right"
                Name="buttonSubmit" VerticalAlignment="Top">
            <Button.Style>
                <Style TargetType="{x:Type Button}">
                    <Setter Property="IsEnabled" Value="false" />
                    <Style.Triggers>
                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition Binding="{Binding ElementName=TextBoxFirstName, Path=(Validation.HasError)}" Value="false" />
                                <Condition Binding="{Binding ElementName=TextBoxLastName, Path=(Validation.HasError)}" Value="false" />
                                <Condition Binding="{Binding ElementName=TextBoxAge, Path=(Validation.HasError)}" Value="false" />
                                <Condition Binding="{Binding ElementName=TextBoxPhone, Path=(Validation.HasError)}" Value="false" />
                            </MultiDataTrigger.Conditions>
                            <Setter Property="IsEnabled" Value="true" />
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
        </Button>
    </Grid>
</Window>

Now, lets look at the supporting objects:

using System.Windows;

namespace WpfTextBoxValidation
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Person p = new Person();
            //PersonViewModel pvm = new PersonViewModel() { Person = p };
            MainGrid.DataContext = p;
        }
    }
}

In The above class, I add an instance of the Person object and make that the DataContext.

using System;

namespace WpfTextBoxValidation
{
    public class Person
    {
        public String FirstName { get; set; }
        public String LastName { get; set; }
        public String Age { get; set; }
        public String Phone { get; set; }
    }
}

The above class is a simple standard person object for examples.

using System;
using System.Windows.Controls;

namespace WpfTextBoxValidation
{
    public class OverThirteenValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            if (value != null)
            {
                int age = 0;
                try
                {
                    age = Convert.ToInt32(value);
                }
                catch
                {
                    return new ValidationResult(false, "You must be older than 13!");
                }

                if (age > 13)
                    return ValidationResult.ValidResult;

            }
            return new ValidationResult(false, "You must be older than 13!");
        }
    }
}

The above class is an example ValidationRule that requires the person be 13 or older.

using System;
using System.Windows.Controls;

namespace WpfTextBoxValidation
{
    public class TextBoxNotEmptyValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            string str = value as string;
            if (str != null)
            {
                if (str.Length > 0)
                    return ValidationResult.ValidResult;
            }
            return new ValidationResult(false, Message);
        }

        public String Message { get; set; }
    }
}

The above class is an example ValidationRule that makes sure a TextBox is not empty.

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace WpfTextBoxValidation
{
    class ErrorCollectionToVisibility : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var collection = value as ReadOnlyCollection<ValidationError>;
            if (collection != null && collection.Count > 0)
                return Visibility.Visible;
            else
                return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return new object();
        }
    }
}

In the above class, I am using a converter to change to Visibility.Visible if there are no errors or change to Visibility.Collapsed if there is one or more errors.

With this simple project you should be able to now have a form in WPF with ValidationRules and disable the submit button should there be an ValidationErrors.

How to change language at run-time in WPF with loadable Resource Dictionaries and DynamicResource Binding

Update: I created a project for this. It also has a NuGet package. 
See https://github.com/rhyous/WPFSharp.Globalizer.

Dynamically changing the language of a WPF application at run-time or on-the-fly is possible and quite simple.

With this solution you do not have Resources.resx files, you do not have to have x:Uid on all your XAML tags. See the expectations this solution is following here: My WPF Localization and Language Expectations. Most of my expectations are met with this solution.

Here is the sample project code: How to load a DictionaryStyle.xaml file at run time?

  • How to: Use a ResourceDictionary to Manage Localizable String Resources
  • Example 1 – Dynamic Localization in WPF with Code-behind

    Step 1 – Create a new WPF Application project in Visual Studio

    1. In Visual Studio, go to File | New | Project.
    2. Select WPF Application.
    3. Provide a name for the project and make sure the path is correct.
    4. Click OK.

    Step 2 – Configure App.xaml.cs to support dynamic ResourceDictionary loading

    The App.xaml.cs is empty by default. We are going to add a few variables, a constructor, and add a few simple functions. This is a fairly small amount of code.

    1. Open App.xaml.cs.
    2. Add a static member variable for App called Instance, so it can be accesses from anywhere.
    3. Add a static member variable for App called Directory, so it can be accesses from anywhere.
    4. Add a LanguageChangedEvent.
    5. Add a private GetLocXAMLFilePath(string inFiveCharLang) method.
    6. Add a public SwitchLanguage(string inFiveCharLanguage) method.
    7. Add a private SetLanguageResourceDictionary(string inFile) method.
    8. Add code to the constructor to initialize these variables and to set the default language.Note: The code is well commented.
      using System;
      using System.Globalization;
      using System.IO;
      using System.Threading;
      using System.Windows;
      
      namespace WpfRuntimeLocalizationExample
      {
          /// <summary>
          /// Interaction logic for App.xaml
          /// </summary>
          public partial class App : Application
          {
              #region Member variables
              public static App Instance;
              public static String Directory;
              public event EventHandler LanguageChangedEvent;
              #endregion
      
              #region Constructor
              public App()
              {
                  // Initialize static variables
                  Instance = this;
                  Directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
      
                  // Load the Localization Resource Dictionary based on OS language
                  SetLanguageResourceDictionary(GetLocXAMLFilePath(CultureInfo.CurrentCulture.Name));
              }
      
              #endregion
      
              #region Functions
              /// <summary>
              /// Dynamically load a Localization ResourceDictionary from a file
              /// </summary>
              public void SwitchLanguage(string inFiveCharLang)
              {
                  if (CultureInfo.CurrentCulture.Name.Equals(inFiveCharLang))
                      return;
      
                  var ci = new CultureInfo(inFiveCharLang);
                  Thread.CurrentThread.CurrentCulture = ci;
                  Thread.CurrentThread.CurrentUICulture = ci;
      
                  SetLanguageResourceDictionary(GetLocXAMLFilePath(inFiveCharLang));
                  if (null != LanguageChangedEvent)
                  {
                      LanguageChangedEvent(this, new EventArgs());
                  }
              }
      
              /// <summary>
              /// Returns the path to the ResourceDictionary file based on the language character string.
              /// </summary>
              /// <param name="inFiveCharLang"></param>
              /// <returns></returns>
              private string GetLocXAMLFilePath(string inFiveCharLang)
              {
                  string locXamlFile = "LocalizationDictionary." + inFiveCharLang + ".xaml";
                  return Path.Combine(Directory, inFiveCharLang, locXamlFile);
              }
      
              /// <summary>
              /// Sets or replaces the ResourceDictionary by dynamically loading
              /// a Localization ResourceDictionary from the file path passed in.
              /// </summary>
              /// <param name="inFile"></param>
              private void SetLanguageResourceDictionary(String inFile)
              {
                  if (File.Exists(inFile))
                  {
                      // Read in ResourceDictionary File
                      var languageDictionary = new ResourceDictionary();
                      languageDictionary.Source = new Uri(inFile);
      
                      // Remove any previous Localization dictionaries loaded
                      int langDictId = -1;
                      for (int i = 0; i < Resources.MergedDictionaries.Count; i++)
                      {
                          var md = Resources.MergedDictionaries[i];
                          // Make sure your Localization ResourceDictionarys have the ResourceDictionaryName
                          // key and that it is set to a value starting with "Loc-".
                          if (md.Contains("ResourceDictionaryName"))
                          {
                              if (md["ResourceDictionaryName"].ToString().StartsWith("Loc-"))
                              {
                                  langDictId = i;
                                  break;
                              }
                          }
                      }
                      if (langDictId == -1)
                      {
                          // Add in newly loaded Resource Dictionary
                          Resources.MergedDictionaries.Add(languageDictionary);
                      }
                      else
                      {
                          // Replace the current langage dictionary with the new one
                          Resources.MergedDictionaries[langDictId] = languageDictionary;
                      }
                  }
              }
              #endregion
          }
      }
      

    Step 3 – Create a basic WPF User Interface

    We need a little sample project to demonstrate the localization, so lets quickly make one.

      1. Create a basic interface.
        Note 1: You can make one yourself, or you can use the basic interface I used. Just copy and paste from below.
        Note 2: I have already added a menu for selecting the Language for you.
    <Window x:Class="WpfRuntimeLocalizationExample.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="WPF Run-time Localization Example"
            MinHeight="350" MinWidth="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="30" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="25" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="15" />
                <ColumnDefinition Width="*" MinWidth="100"/>
                <ColumnDefinition Width="*" MinWidth="200"/>
                <ColumnDefinition Width="15" />
            </Grid.ColumnDefinitions>
            <DockPanel Grid.ColumnSpan="4" >
                <Menu DockPanel.Dock="Top" >
                    <MenuItem Header="_File">
                        <MenuItem Header="E_xit" Click="MenuItem_Exit_Click" />
                    </MenuItem>
                    <MenuItem Name="menuItemLanguages" Header="_Languages">
                        <MenuItem Tag="en-US" Header="_English" Click="MenuItem_Style_Click" />
                        <MenuItem Tag="es-ES" Header="_Spanish" Click="MenuItem_Style_Click" />
                        <MenuItem Tag="he-IL" Header="_Hebrew" Click="MenuItem_Style_Click" />
                    </MenuItem>
                </Menu>
            </DockPanel>
            <Label Content="First Name" Name="labelFirstName" Grid.Row="2" FlowDirection="RightToLeft" Grid.Column="1" />
            <Label Content="Last Name" Name="labelLastName" Grid.Row="4" FlowDirection="RightToLeft" Grid.Column="1" />
            <Label Content="Age" Name="labelAge" Grid.Row="3" FlowDirection="RightToLeft" Grid.Column="1" />
            <TextBox Name="textBox1" Grid.Column="2" Grid.Row="2" />
            <TextBox Name="textBox2" Grid.Column="2" Grid.Row="3" />
            <TextBox Name="textBox3" Grid.Column="2" Grid.Row="4" />
            <Button Content="Clear" Grid.Column="2" Grid.Row="5" Height="23" HorizontalAlignment="Right" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
        </Grid>
    </Window>
    
    1. Also populate the MainWindow.xaml.cs file with the code-behind needed for the menu click events.
      using System;
      using System.Globalization;
      using System.Windows;
      using System.Windows.Controls;
      
      namespace WpfRuntimeLocalizationExample
      {
          /// <summary>
          /// Interaction logic for MainWindow.xaml
          /// </summary>
          public partial class MainWindow : Window
          {
              public MainWindow()
              {
                  InitializeComponent();
                  foreach (MenuItem item in menuItemLanguages.Items)
                  {
                      if (item.Tag.ToString().Equals(CultureInfo.CurrentUICulture.Name))
                          item.IsChecked = true;
                  }
              }
      
              private void MenuItem_Exit_Click(object sender, RoutedEventArgs e)
              {
                  Environment.Exit(0);
              }
      
              private void MenuItem_Style_Click(object sender, RoutedEventArgs e)
              {
                  // Uncheck each item
                  foreach (MenuItem item in menuItemLanguages.Items)
                  {
                      item.IsChecked = false;
                  }
      
                  MenuItem mi = sender as MenuItem;
                  mi.IsChecked = true;
                  App.Instance.SwitchLanguage(mi.Tag.ToString());
              }
      
              private void button1_Click(object sender, RoutedEventArgs e)
              {
                  labelFirstName.Content = labelLastName.Content = labelAge.Content = string.Empty;
              }
          }
      }
      

    Though localization is not yet working, this should compile and run.

    Step 4 – Create Resource Dictionaries for Localization

    By recommendation of my expert localization team, we are going to create a folder for each language, using the five character string (en-US, es-ES, he-IL), and put a ResourceDictionary in each folder. The resource dictionary will also have the five character language string.

    1. Create the folder and the file.
      1. Right-click on the project in Visual Studio and choose Add | New Folder.
      2. Name the folder en-US
      3. Right-click on the en-US folder and choose Properties.
      4. Set the ‘Namespace Provider’ value to false.
      5. Right-click on the en-US folder and choose Add | Resource Dictionary.
      6. Provide a file name and make sure that Resource Dictionary (WPF) is selected.
      7. Note: I named my first resource dictionary LocalizationDictionary.en-US.xaml.
      8. Click Add.
      9. Right-click on the LocalizationDictionary.en-US.xaml file and choose Properties.
      10. Set ‘Build Action’ to ‘Content’.
      11. Set ‘Copy to Output Directory’ to be ‘Copy if newer’.
      12. Set ‘Custom Tool’ to blank.
    2. Name the ResourceDictionary.
      1. Open the resource LocalizationDictionary.en-US.xaml
      2. Add a reference to the System namespace from the mscorlib assembly.
      3. Add a string with the x:Key set to ResourecDictionaryName.
      4. Set the string value to “Loc-en-US”.
        Important! Because our code is specifically looking for Loc-, you need to use that scheme or change the code.
      5. Add to the string a Localization.Comment and set the value to $Content(DoNotLocalize).
      6. Save the resource dictionary.
        <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                            xmlns:sys="clr-namespace:System;assembly=mscorlib">
        
            <!-- The name of this ResourceDictionary. Should not be localized. -->
            <sys:String x:Key="ResourceDictionaryName" Localization.Comments="$Content(DoNotLocalize)">Loc-en-US</sys:String>
        
        </ResourceDictionary>
        
    3. Repeat all the steps in steps 1 and 2 for each langauge.
      Note: We will do the following three languages in this example:

      1. en-US
      2. es-ES
      3. he-IL

    Step 4 – Localize the strings

    We now are going to find each string that needs to be localized, add a string resource in our localization resource dictionary, and replace the string with DynamicResource binding.
    1. Open the MainWindow.xaml.
    2. The first string is the Title of the Window.
      Note: My window title is “WPF Run-time Localization Example”
    3. Replace the value with a DynamicResource to MainWindow_Title.
      Here is a snippet…

      <Window x:Class="WpfRuntimeLocalizationExample.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="{DynamicResource ResourceKey=MainWindow_Title}"
              MinHeight="350" MinWidth="525">
          <Grid>
      
    4. Open the LocalizationDictionary.en-US.xaml.
    5. Add a string as a resource for the MainWindow’s  Title, making sure the x:Key value is matches the ResourceKey in the MainWindow.xaml: MainWindow_Title.
          <!-- Localized strings -->
          <sys:String x:Key="MainWindow_Title">WPF Run-time Localization Example</sys:String>
      
    6. Repeat steps for each of the remaining string that needs to be localized.
      The following strings need to be localized in my sample UI:

      1.  _File
      2. E_xit
      3. _Language
      4. _English
      5. _Spanish
      6. _Hebrew
      7. First Name
      8. Last Name
      9. Age
      10. Clear
    You program should now compile and switch language.

    Step 5 – Configure the FlowDirection

    The main motivation for adding Hebrew to this example is so that we can show how to dynamically switch FlowDirection for languages that flow from right to left.

    Note: This step is optional and only necessary if your application will support a language that flows right to left.

    1. Add two FlowDirection resources to the LocalizationDictionary.en-US.xaml files.
          <!-- Localization specific styles -->
          <FlowDirection x:Key="FlowDirection_Default" Localization.Comments="$Content(DoNotLocalize)">LeftToRight</FlowDirection>
          <FlowDirection x:Key="FlowDirection_Reverse" Localization.Comments="$Content(DoNotLocalize)">RightToLeft</FlowDirection>
      
    2. For Spanish, copy these same lines to the LocalizationDictionary.es-ES.xaml file. Spanish and English have the same FlowDirection.
    3. For Hebrew, (you have probably already guessed this), add these same lines to the LocalizationDictionary.he-IL.xaml file but reverse the values.
          <!-- Localization specific styles -->
          <FlowDirection x:Key="FlowDirection_Default" Localization.Comments="$Content(DoNotLocalize)">RightToLeft</FlowDirection>
          <FlowDirection x:Key="FlowDirection_Reverse" Localization.Comments="$Content(DoNotLocalize)">LeftToRight</FlowDirection>
      
    4. Open the MainWindow.xaml file.
    5. Add a FlowDirection tag to the MainWindow.xaml file.
    6. Set the FlowDirection value to using DynamicResource binding to FlowDirection_Default.Here is the XAML snipppet.
      <Window x:Class="WpfRuntimeLocalizationExample.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="{DynamicResource MainWindow_Title}"
              MinHeight="350" MinWidth="525"
              FlowDirection="{DynamicResource FlowDirection_Default}">
          <Grid>
      

    Build compile and test. Both the language and FlowDirection should now change when switching to Hebrew.

    See the Framework for this here:

    https://github.com/rhyous/WPFSharp.Globalizer

    Resources

    A snippet for Properties in a ViewModel

    If you are using MVVM you probably should create a snippet very similar to the following to save time.

    C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC#\Snippets\1033\Visual C#\propvm.snippet

    <?xml version="1.0" encoding="utf-8" ?>
    <CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    	<CodeSnippet Format="1.0.0">
    		<Header>
    			<Title>propvm</Title>
    			<Shortcut>propvm</Shortcut>
    			<Description>Code snippet for property and backing field for a ViewModel that calls NotifyPropertyChanged.</Description>
    			<Author>Jared Barneck</Author>
    			<SnippetTypes>
    				<SnippetType>Expansion</SnippetType>
    			</SnippetTypes>
    		</Header>
    		<Snippet>
    			<Declarations>
    				<Literal>
    					<ID>type</ID>
    					<ToolTip>Property type</ToolTip>
    					<Default>int</Default>
    				</Literal>
    				<Literal>
    					<ID>property</ID>
    					<ToolTip>Property name</ToolTip>
    					<Default>MyProperty</Default>
    				</Literal>
    			</Declarations>
    			<Code Language="csharp"><![CDATA[public $type$ $property$
    	{
    		get { return _$property$;}
    		set 
    		{ 
    			_$property$ = value;
    			NotifyPropertyChanged("$property$");
    		}
    	} private $type$ _$property$;
    	$end$]]>
    			</Code>
    		</Snippet>
    	</CodeSnippet>
    </CodeSnippets>
    

    WPF Binding to a property of a static class

    Binding to a property of a static class is quite straight forward.

    The binding string looks like this:

    {x:Static s:MyStaticClass.StaticValue2}

    For an example do this:

    1. Create a new folder in your project called Statics.
    2. Add the following class to the Statics folder.
      using System;
      
      namespace BindingToStaticClassExample.Statics
      {
          public static class MyStaticClass
          {
              static MyStaticClass()
              {
                  Title = "Binding to properties of Static Classes";
                  StaticValue1 = "Test 1";
                  StaticValue2 = "Test 2";
                  StaticValue3 = "Test 3";
              }
      
              public static String Title { get; set; }
              public static String StaticValue1 { get; set; }
              public static String StaticValue2 { get; set; }
              public static String StaticValue3 { get; set; }
          }
      }
      
    3. Add a reference to the BindingToStaticClassExample.Statics namespace. (See line 4.)
    4. Bind the title to the Title string value of MyStaticClass.
    5. Change the <Grid> to a <StackPanel> (not required just for ease of this example).
    6. Add TextBox elements and bind them to the two string values in MyStaticClass object.
      <Window x:Class="BindingToStaticClassExample.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:s="clr-namespace:BindingToStaticClassExample.Statics"
              Title="{x:Static s:MyStaticClass.Title}" Height="350" Width="525">
          <StackPanel>
              <TextBox Text="{x:Static s:MyStaticClass.StaticValue1}" />
              <TextBox Text="{x:Static s:MyStaticClass.StaticValue2}" />
              <!-- Not supported and won't work
              <TextBox>
                  <TextBox.Text>
                      <Binding Source="{x:Static s:MyStaticClass.StaticValue3}" />
                  </TextBox.Text>
              </TextBox>
              -->
          </StackPanel>
      </Window>
      

    You now know how to bind to properties of a static class.

    WPF Binding to a property of a static class

    Binding to a property of a static class is quite straight forward.

    The binding string looks like this:

    {x:Static s:MyStaticClass.StaticValue2}

    For an example do this:

    1. Create a new folder in your project called Statics.
    2. Add the following class to the Statics folder.
      using System;
      
      namespace BindingToStaticClassExample.Statics
      {
          public static class MyStaticClass
          {
              static MyStaticClass()
              {
                  Title = "Binding to properties of Static Classes";
                  StaticValue1 = "Test 1";
                  StaticValue2 = "Test 2";
                  StaticValue3 = "Test 3";
              }
      
              public static String Title { get; set; }
              public static String StaticValue1 { get; set; }
              public static String StaticValue2 { get; set; }
              public static String StaticValue3 { get; set; }
          }
      }
      
    3. Add a reference to the BindingToStaticClassExample.Statics namespace. (See line 4.)
    4. Bind the title to the Title string value of MyStaticClass.
    5. Change the <Grid> to a <StackPanel> (not required just for ease of this example).
    6. Add TextBox elements and bind them to the two string values in MyStaticClass object.
      <Window x:Class="BindingToStaticClassExample.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:s="clr-namespace:BindingToStaticClassExample.Statics"
              Title="{x:Static s:MyStaticClass.Title}" Height="350" Width="525">
          <StackPanel>
              <TextBox Text="{x:Static s:MyStaticClass.StaticValue1}" />
              <TextBox Text="{x:Static s:MyStaticClass.StaticValue2}" />
              <!-- Not supported and won't work
              <TextBox>
                  <TextBox.Text>
                      <Binding Source="{x:Static s:MyStaticClass.StaticValue3}" />
                  </TextBox.Text>
              </TextBox>
              -->
          </StackPanel>
      </Window>
      

    You now know how to bind to properties of a static class.

    A quick overview of MVVM

    Model View ViewModel (MVVM) is a design pattern based on Model View Controller (MVC) but specifically tailored to Windows Presentation Foundation (WPF).

    MVVM is not a framework per se but many frameworks have been created. Here is a list of MVVM Frameworks from Wikipedia.

    See the Wikipedia site here: Open Source MVVM Frameworks.

    Another blog, has some basic information on many of these here: A quick tour of existing MVVM frameworks

    A framework is actually not necessary to implement MVVM and you should seriously consider whether using one is right for your WPF application or not. Many applications do not need much of the features the frameworks provide. However, there are two common classes that all MVVM frameworks contain. These are ViewModelBase and RelayCommand. Though some frameworks may give them different names or implement them slightly differently, they all have these classes. For example, MVVM Foundation names the ViewModelBase differently. It is called ObservableObject, which is more appropriate because it is incorrect to assume that all objects that implement INotifyPropertyChanged are going to be ViewModel objects.

    Instead of installing and using an MVVM framework, you could simply include these classes in your application, as these are all you need to implement MVVM.

    • ObservableObject
    • RelayCommand

    While these two classes are enough, you may want to investigate how different MVVM Frameworks implement and what else they implement and why. You may find that another feature implemented is exactly what you need in your application and knowing about it could save you time.