Archive for the ‘XAML’ Category.

Why XAML is here to stay

Declarative user interfaces that support binding allow for decoupling the visual presentation of an application from the back end, which is often code, databases, files, or a combination of all of them.

This decoupling leads to easy maintainability.

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.[1You 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.

ItemsControl vs ListBox vs ListView in WPF

I wanted to highlight some of the similarities and some of the differences of ListBox vs ItemsControl.

Similarites of ItemsControl, ListBox, and ListView

These two controls are similar in a few ways.

  • All three are lists
  • All three support binding ItemsSource to a list
  • All three are ItemsControl objects as ListBox and ListView are descendants

Differences between ItemsControl, ListBox, and ListView

Inheritence

ItemsControl

ItemsControl uses an ItemsPresenter to present its children.

System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.FrameworkElement
System.Windows.Controls.Control
System.Windows.Controls.ItemsControl

ListBox

A ListBox is an ItemsControl but an ItemsControl is not a list box. Notice a list box is a descendant of ItemsControl but has a Selector object, which is abstract, that it specifically derives from. Inheriting from Selector provides ListBox with selection events and selection features that are missing from ItemsControl. ListBox adds a SelectionMode Dependency Property that allows for selection types of Single, Multiple, or Extended, which are defined in a SelectionMode enum. It uses ListBoxItem as its default child.


System.Windows.Controls.ItemsControl
System.Windows.Controls.Primitives.Selector
System.Windows.Controls.ListBox

ListView

ListView inherits from ListBox, so it is everything a ListBox is plus it has a View Dependency Property and some functions supporting the View Dependency Property. It uses ListViewItem as its default child.


System.Windows.Controls.ItemsControl
System.Windows.Controls.Primitives.Selector
System.Windows.Controls.ListBox
System.Windows.Controls.ListView

Sizing and Scrolling

  • ItemsControl takes as much space as it needs for its child elements, which can cause it to be larger than the screen. Because its size is based on its child controls, ItemsControl does not resize when re-sizing the screen.
  • ListBox and ListView take up all the space available to them from the parent and no more. Because the size is based on the parent control size, ListBox and ListView resize with the screen.
  • ItemsControl does not have a ScrollBar.
  • ListBox has both a vertical and horizontal ScrollBar.
Note: I learned that if you want to have an ItemsControl, but you want to have the scrolling. Simply make a copy of the ListBox style and change its TargetType to ItemsControl and use that style.

Styles and Templates

Note: These default styles are obtained using Expresion Blend by right-clicking a Control and choosing Edit Template | Edit a copy.

ItemsControl Default Style

This style is short and simple.

<ResourceDictionary
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<Style x:Key="ItemsControlDefaultStyle" TargetType="{x:Type ItemsControl}">
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type ItemsControl}">
					<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
						<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
					</Border>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
	<!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>

ListBox and ListView Default Style

ListBox and ListView have the same default style, with the only exception being the the TargetType, which is of course ListBox or ListView repectively.

Both have all the elements ItemsControl has, but also there are more Setters as Setters exist for the ScrollViewer and for the Border. ListBox and ListView styles also include a ScrollViewer in the ControlTemplate between the Border and the ItemsPresenter. ListBox and ListView also have a ControlTemplate.Triggers section.

<ResourceDictionary
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
	<Style x:Key="ListBoxDefaultStyle" TargetType="{x:Type ListBox}">
		<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
		<Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
		<Setter Property="BorderThickness" Value="1"/>
		<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
		<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
		<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
		<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
		<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
		<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
		<Setter Property="VerticalContentAlignment" Value="Center"/>
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type ListBox}">
					<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
						<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
							<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
						</ScrollViewer>
					</Border>
					<ControlTemplate.Triggers>
						<Trigger Property="IsEnabled" Value="false">
							<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
						</Trigger>
						<Trigger Property="IsGrouping" Value="true">
							<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
						</Trigger>
					</ControlTemplate.Triggers>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
	<!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>

Note: If you accidentally put ListBoxItems under ListView, the items are wrapped in a ListViewItem control which has its own margin, which will make the items move 5 pixels further to the right.

Choosing betweeen ItemsControl, ListBox, and ListView

Choosing an ItemsControl

It is pretty easy to choose between ItemsControl and either ListBox or ListView. If you do not want the ability to select a row or switch the View, use ItemsControl. Otherwise, use ListBox or ListView.

Choosing an ListBox

Also, if you need the select feature but you do not need to be able to switch the View, use ListBox.

Choosing an ListView

If you need to be able to switch the View, then choose ListView. It doesn’t matter if you need the ability to select or not.

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 load a ResourceDictionary at Design Time in WPF

I am including my ResourceDictionary files as Content files. Content files means they are not compiled or embedded, but they are loose files on disk.

One issue I need to solve was how to have the Design View in Expression Blend or Visual Studio.

It seems that Expression Blend has a partial solution but it doesn’t work in Visual Studio for me.

Steps for loading a ResourceDictionary from a loose file at design time

  1. Locate your .proj file for your WPF Project.
  2. Edit the .proj file with you favorite text editor.
    Note: I use Notepad++.
  3. Find the ResourceDictionary file that is included as content.
        <Content Include="Resources\en-US\Common.View.LocalizationResources.en-US.xaml">
          <Generator>MSBuild:Compile</Generator>
          <SubType>Designer</SubType>
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
    
  4. Change it to this:
        <Content Include="Resources\en-US\Common.View.LocalizationResources.en-US.xaml"
          Condition="'$(DesignTime)'=='true'
          OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)')
          AND '$(BuildingInsideVisualStudio)'!='true'
          AND '$(BuildingInsideExpressionBlend)'!='true')">
          <Generator>MSBuild:Compile</Generator>
          <SubType>Designer</SubType>
          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
        </Content>
    
  5. Save and close the file.

 

Loading multiple ResourceDictionary files at design time

Sometimes Expression Blend will prompt you when it can’t find a resource and it will do this for you. However, it does something interesting.

It adds a file called DesignTimeResources.xaml in the Properties folder as a Page (not as Content).

    <Page Include="Properties\DesignTimeResources.xaml" 
      Condition="'$(DesignTime)'=='true' 
      OR ('$(SolutionPath)'!='' 
      AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' 
      AND '$(BuildingInsideExpressionBlend)'!='true')">
      <Generator>MSBuild:Compile</Generator>
      <SubType>Designer</SubType>
      <ContainsDesignTimeResources>true</ContainsDesignTimeResources>
    </Page>

The file then looks as follows:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>        
        <ResourceDictionary Source="E:\Dev\LD\Trunk\install\Common\LANDesk.Install.Common\Resources\en-US\Common.LocalizationResources.en-US.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>

And then you can add more ResourceDictionaries without modifying the .proj file.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="E:\Dev\LD\Trunk\install\SomeApp\Branding\StyleResources.xaml"/>
        <ResourceDictionary Source="E:\Dev\LD\Trunk\install\SomeApp\Branding\AlternateStyleResources.xaml"/>
        <ResourceDictionary Source="E:\Dev\LD\Trunk\install\SomeApp\Resources\en-US\en-US.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>

ResourceDictionary with Relative Paths

Of course relative paths are more desired than static paths, especially when using projects among multiple people and from source control.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="..\Branding\StyleResources.xaml"/>
        <ResourceDictionary Source="..\Branding\AlternateStyleResources.xaml"/>
        <ResourceDictionary Source="..\Resources\en-US\en-US.xaml"/>
    </ResourceDictionary.MergedDictionaries>
    <!-- Resource dictionary entries should be defined here. -->
</ResourceDictionary>

Resources:
http://www.tweened.org/en/2010/06/07/design-time-resources-dans-blend-4/

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

    My WPF Localization and Language Expectations

    WPF Localization and Language switching at run-time is not exactly solved clearly by Microsoft.  After my experience (which includes researching for days on separate occasions and changing to localize using Resources.resx when localizing with BAML was not working for everyone involved) I had come to the conclusion that WPF Localization was just going to remain a black mark on WPF until Microsoft provided an easy recommended solution.

    Microsoft has a lot of information on localization.  They have pages and pages of it and a lot of talks about localization using Resources.resx or using BAML (Binary XAML).

    I came to realize that I had the following expectations:

    1. Development for Localization should be easy.
    2. Development for Localization should not require “extra” libraries or separate projects.
    3. Localized strings should come from the same place for XAML as for C# code.
    4. Language switching should be a run-time option.
    5. Localization changes should not require a rebuild or recompile.
    6. Localization method should allow for us of a localization tool (such as Alchemy Catalyst).
    7. Localization should not require every item has an a unique identifier (as in no x:Uid tags in WPF).
    8. Missing strings in any language should be easily identified.
    9. FlowDirection should change with language when appropriate (such as for Hebrew).

    Neither the Resources.resx or the XAML solutions seemed to meet my expectations.

    Time came to decide on a localization method for WPF again, and I again embarked into similar research as before. I found all the same answers.

    However, I am now a WPF Expert. A Senior WPF Developer if you can call anyone such for such a young technology.

    I went through all the same pages as before only this time, I pieced together a localization solution that comes the closest to meeting all my expectations.

    If you don’t agree with most of my expectations, feel free to use another WPF localization solution. I am not going to argue that mine is the best for everyone, just the best for me and my expectations.

    In all my searching I have found no one who is using my solution. Expect my new solution soon and link at the end of this post soon.

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

     

     

    How to load a DictionaryStyle.xaml file at run time?

    Changing a theme or style at run-time is possible by assigning styles using DynamicResource binding and loading a ResourceDictionary (XAML) from a Content file at run-time.

    This can be done by loading a DictionaryStyle.xaml at run time.

    If you would prefer to just jump right in, download the source code: RuntimeLoadOfResourceDictionaryExample.zip

    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 – Create a basic WPF User Interface

    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 Blue or Grey for you.
    2. Set the Style to use DynamicResource binding.
    3. <Window x:Class="RuntimeLoadOfResourceDictionaryExample.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="MainWindow"
              Style="{DynamicResource ResourceKey=MainWindowStyle}"
              >
          <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 Header="_Styles">
                          <MenuItem Name="BlueStyle" Header="_Blue" Click="MenuItem_Style_Click" />
                          <MenuItem Name="GreyStyle" Header="_Grey" Click="MenuItem_Style_Click" />
                      </MenuItem>
                  </Menu>
              </DockPanel>
              <Label Content="First Name" Name="label1" Grid.Row="2" FlowDirection="RightToLeft" Grid.Column="1" />
              <Label Content="Age" Name="label3" Grid.Row="3" FlowDirection="RightToLeft" Grid.Column="1" />
              <Label Content="Last Name" Name="label2" Grid.Row="4" 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" />
          </Grid>
      </Window>
      
    4. Also populate the MainWindow.xaml.cs file with the code-behind needed for some of the events.
              private void MenuItem_Exit_Click(object sender, RoutedEventArgs e)
              {
                  Environment.Exit(0);
              }
      
              private void MenuItem_Style_Click(object sender, RoutedEventArgs e)
              {
                  MenuItem mi = sender as MenuItem;
                  string stylefile = Path.Combine(App.Directory, "Styles", mi.Name + ".xaml");
                  App.Instance.LoadStyleDictionaryFromFile(stylefile);
              }
      
    5. It won’t compile just yet as some of the code doesn’t exist yet.

    Step 3 – Add code to read in a ResourceDictionary at runtime

    This is going to take place in the App.xaml.cs file. App.xaml.cs is the ultimate parent and by loading the ResourceDictionary here, every child will have access to them. This especially becomes important with larger projects where WPF UI elements, controls, windows, or others may come from other dlls.

    1. Open the App.xam.cs file as shown below.
    2. Add a function to load the ResourceDictionary at runtime.
    3. Now add some member variables and create a constructor that loads a style by default.Your class should now look as follows:
      using System;
      using System.IO;
      using System.Windows;
      using System.Windows.Markup;
      
      namespace RuntimeLoadOfResourceDictionaryExample
      {
          /// <summary>
          /// Interaction logic for App.xaml
          /// </summary>
          public partial class App : Application
          {
              public static App Instance;
              public static String Directory;
              private String _DefaultStyle = "BlueStyle.xaml";
      
              public App()
              {
                  Instance = this;
                  Directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
                  string stringsFile = Path.Combine(Directory, "Styles", _DefaultStyle);
                  LoadStyleDictionaryFromFile(stringsFile);
              }
      
              /// <summary>
              /// This funtion loads a ResourceDictionary from a file at runtime
              /// </summary>
              public void LoadStyleDictionaryFromFile(string inFileName)
              {
                  if (File.Exists(inFileName))
                  {
                      try
                      {
                          using (var fs = new FileStream(inFileName, FileMode.Open, FileAccess.Read, FileShare.Read))
                          {
                              // Read in ResourceDictionary File
                              var dic = (ResourceDictionary)XamlReader.Load(fs);
                              // Clear any previous dictionaries loaded
                              Resources.MergedDictionaries.Clear();
                              // Add in newly loaded Resource Dictionary
                              Resources.MergedDictionaries.Add(dic);
                          }
                      }
                      catch
                      {
                      }
                  }
              }
          }
      }
      

    Now, we haven’t create the default style yet, don’t fret, that is the next step.

    Step 4 – Create Some Styles

    1. In Visual Studio, add a new folder to your project called Styles.
    2. Right-click on the folder and choose Properties.
    3. Set the Namespace Provider value to false.
    4. Right-click on the Styles folder and choose Add | Resource Dictionary.
    5. Provide a file name and make sure that Resource Dictionary (WPF) is selected.
      Note: I named my first resource dictionary BlueStyle.xaml.
    6. Click Add.
    7. Right-click on the BlueStyle.xaml file and choose Properties.
    8. Set ‘Build Action’ to ‘Content’.
    9. Set ‘Copy to Output Directory’ to be ‘Copy if newer’.
    10. Set ‘Custom Tool’ to blank.
    11. Populate the BlueStyle.xaml with your desired style. Here is the simple style I used for this example.
      <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
          <Style x:Key="MainWindowStyle" TargetType="Window">
              <Setter Property="SizeToContent" Value="WidthAndHeight" />
              <Setter Property="Background" Value="RoyalBlue" />
          </Style>
          <Style TargetType="Label">
              <Setter Property="Margin" Value="0,5,0,5" />
          </Style>
          <Style TargetType="TextBox">
              <Setter Property="Margin" Value="0,5,0,5" />
          </Style>
      </ResourceDictionary>
      
    12. Create a copy of the style named GreyStyle.xaml.
    13. Repeat steps 7 thru 10 for this new file.
    14. In the GreyStyle.xaml, change the Background of the MainWindowStyle to DarkGrey.

    Step 5 – Build and test

    Your project should now be working.  You should be able to build and run it.  You should be able to click on Styles and change the style.

    Using relative path images included as content with WPF

    Many people want to include an image but for reasons such as the ability to change branding, the image should not be compiled in.

    Step 1 – Create a new WPF Application project

    For most, you don’t need steps to create a project, but just in case you are creating a WPF project for the first time, here are the steps.

    1. Open Visual Studio and go to File | New | Project.
    2. Select WPF Application.
    3. Provide a name and location.
    4. Click OK.

    Step 2 – Add an image as Content to the project

    Were are going to create a folder called images and put the image there.

    1. Right-click on the project and choose Add | New Folder.
    2. Name the folder Images.
    3. Right-click on the Images folder and choose Add | Existing Item.
    4. Choose an image from your file system and click Add. Note: I used the sword.png image from my blog for this example.
    5. Right-click on your image file and choose Properties.
    6. Change the Build Action to Content.
    7. Change the Copy to Output Directory to Copy of Newer.

    Step 3 – Add the image to XAML using a relative path URI

    1. Change the Window to size to content and added a MinWidth and MinHeight as shown on lines 5 and 6. Note: This step wasn’t required, but I did it.
    2. Add an image to the MainWindow.xaml as shown on line 8.
      <Window x:Class="RelativePathImages.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="MainWindow" 
              SizeToContent="WidthAndHeight"
              MinHeight="200" MinWidth="300">
          <Grid>
              <Image />
          </Grid>
      </Window>
      
    3. Configure the Source of the image to be the relative path using a Pack URI. See this article on MSDN for more information on Pack URIs: Pack URIs in WPF
          <Grid>
              <Image Source="pack://siteoforigin:,,,/Images/Sword.png" MaxWidth="1024"/>
          </Grid>
      

      Note: I also added a MaxWidth to the image because the resolution was huge.

    4. Build and run your project.

    Your image is now loaded from whatever image is located in the relative path from your executable. Note: Another option for doing this includes using a ViewModel and binding.

    How use access modifiers (internal, private, public) in XAML with WPF

    You can configure the access modifier of objects defined in XAML using x:FieldModifier.

    <TextBox Name="MyInternalTextBox" x:FieldModifier="internal" />
    <TextBox Name="MyPrivateTextBox" x:FieldModifier="private" />
    <TextBox Name="MyPrivateTextBox" x:FieldModifier="protected" />
    <TextBox Name="MyPublicTextBox" x:FieldModifier="public" />