Archive for the ‘XAML’ Category.

A FileTextBox control in WPF

Have you ever wanted a text file to be displayed in readonly fashion in a WPF window? Perhaps you have a log file and you want the UI to stay synced with the log updates to the file? Maybe you simply want to write a WPF version of WinTail?

Well, I just wrote a control in which you can set file path to a DependencyProperty and the UI will stay up to date. I created a child of TextBox called FileTextBox and implemented FileSystemWatcher.

Update: 6/16/2014 – Added AutoScroll.

using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;

namespace WpfSharp.UserControls
{
    public class FileTextBox : TextBox
    {
        #region Private fields
        private bool _ChangedHandlerAdded;
        private bool _CreatedHandlerAdded;
        private bool _DeletedHandlerAdded;
        private bool _RenameHandlerAdded;
        #endregion

        #region constructor
        public FileTextBox()
        {
            AcceptsReturn = true;
            IsReadOnly = true;
            AutoScroll = true;
        }
        #endregion

        #region Properties
        /// <summary>
        /// If true, the FileTextBox will always scroll to the end when updated.
        /// </summary>
        public bool AutoScroll { get; set; }
        #endregion

        #region File Dependency Property
        public string File
        {
            get { return (string)GetValue(FileProperty); }
            set { SetValue(FileProperty, value); }
        }

        // Using a DependencyProperty as the backing store for File.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FileProperty =
            DependencyProperty.Register("File", typeof(string), typeof(FileTextBox), new FrameworkPropertyMetadata(OnFilePropertyChanged));

        private static void OnFilePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var ftb = sender as FileTextBox;
            if (ftb == null || args.NewValue == null || string.IsNullOrWhiteSpace(args.NewValue.ToString()))
            {
                return;
            }
            var dir = GetDirectory(ref args);
            if (!string.IsNullOrWhiteSpace(dir) && Directory.Exists(dir))
            {
                ftb.Watcher.Path = Path.GetDirectoryName(args.NewValue.ToString());
                ftb.Watcher.Filter = Path.GetFileName(args.NewValue.ToString());
                ftb.AddEvents();
                ftb.Watcher.EnableRaisingEvents = true;
                ftb.UpdateFile();
            }
            else
            {
                ftb.Text = string.Empty;
            }
        }

        private static string GetDirectory(ref DependencyPropertyChangedEventArgs args)
        {
            try
            {
                return Path.GetDirectoryName(args.NewValue.ToString());
            }
            catch (Exception)
            {
                return null;
            }
        }
        #endregion

        private FileSystemWatcher Watcher
        {
            get { return _Watcher ?? (_Watcher = BuildWatcher()); }
        } private FileSystemWatcher _Watcher;

        private FileSystemWatcher BuildWatcher()
        {
            var watcher = new FileSystemWatcher { NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName };
            return watcher;
        }

        public void OnFileDeleted(object sender, FileSystemEventArgs e)
        {
            Dispatcher.Invoke(UpdateFile);
        }

        public void OnFileChanged(object sender, FileSystemEventArgs e)
        {
            Dispatcher.Invoke(UpdateFile);
        }

        public void OnFileCreated(object sender, FileSystemEventArgs e)
        {
            Dispatcher.Invoke(() =>
            {
                UpdateFile();
                EnableRaiseEvents();
            });
        }

        public void OnFileRenamed(object sender, RenamedEventArgs e)
        {
            Dispatcher.Invoke(UpdateFile);
        }

        private void EnableRaiseEvents()
        {
            Dispatcher.Invoke(() =>
            {
                if (!Watcher.EnableRaisingEvents)
                    Watcher.EnableRaisingEvents = true;
            });
        }

        private void UpdateFile()
        {
            if (!System.IO.File.Exists(File))
            {

                Text = string.Empty;
                return;
            }
            using (var fs = new FileStream(File, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (var sr = new StreamReader(fs))
                {
                    Text = sr.ReadToEnd();
                    if (AutoScroll)
                        ScrollToEnd();
                }
            }
        }

        private void AddEvents()
        {
            if (!_CreatedHandlerAdded)
            {
                Watcher.Created += OnFileCreated;
                _CreatedHandlerAdded = true;
            }
            if (!_ChangedHandlerAdded)
            {
                Watcher.Changed += OnFileChanged;
                _ChangedHandlerAdded = true;
            }
            if (!_DeletedHandlerAdded)
            {
                Watcher.Deleted += OnFileDeleted;
                _DeletedHandlerAdded = true;
            }
            if (!_RenameHandlerAdded)
            {
                Watcher.Renamed += OnFileRenamed;
                _RenameHandlerAdded = true;
            }
        }
    }
}

As always, feedback is appreciated.

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.

A simple TrimmedTextBox for WPF

So I wanted a TextBox that trims automatically. At first I played with the idea of a converter, but that just didn’t work out. Try using a trim converter with UpdateSourceTrigger=PropertyChanged and you will see what I mean. Yes, it seems you cannot even type a space. I need the trimming to occur after losing focus.

After thinking about it, a converter was the wrong method anyway. If I want a TextBox that always trims when it loses focus, why not just make one by inheriting from TextBox and adding a method to the LostFocus event. So I did.

using System.Windows.Controls;

namespace WpfSharp.UserControls
{
    public class TrimmedTextBox : TextBox
    {
        public TrimmedTextBox()
        {
            LostFocus += TrimOnLostFocus;
        }

        void TrimOnLostFocus(object sender, System.Windows.RoutedEventArgs e)
        {
            var trimTextBox = sender as TrimmedTextBox;
            if (trimTextBox != null)
                trimTextBox.Text = trimTextBox.Text.Trim();
        }
    }
}

Now to use this in XAML, add this namespace to your UserControl or Window:

xmlns:wpfsharp="clr-namespace:WpfSharp.UserControls;assembly=WpfSharp"

Then use the object like this:

<wpfsharp:TrimmedTextBox Name="TextBoxAccount" TextWrapping="Wrap" MinWidth="200" Text="{Binding Account}" />

Remember, it is the simple solutions that are best.

WPF will not die if Silverlight does!

I keep hearing in the community that Silverlight and WPF are dead. Why? Well, I think this is because Microsoft is moving to HTML5, CSS, and JavaScript for web apps and is providing that as an option for Windows 8 Metro apps. Because of this, Microsoft may have stopped development on Silverlight.

How does Silverlight affect WPF? It doesn’t! WPF is not a tool for writing web apps. There is a common misconception that the life span of Silverlight and WPF are tied together and if one dies, so does the other. This is far from accurate.

Silverlight != WPF

WPF and Silverlight Similarities

Sure, Silverlight and WPF have similarities. Here are some:

  1. They both use XAML.
  2. They share syntax and often code or XAML written in one works in the other.
  3. They share some code and libraries.

WPF and Silverlight Differences

Let’s look at the differences between WPF and Silverlight. It is in these differences that it becomes obvious that WPF is just beginning a long life as an amazing API for writing rich interfaces.

WPF  (Windows Presentation Foundation)

  1. It is tool for writing full-featured desktop applications that run on Windows.
  2. It is a permanent part of the .NET Framework.
  3. It competes with Windows Forms only for writing desktop applications.
  4. Current applications are being written with WPF, such as VS 2012. Expression Studio. Etc…
  5. Future versions of those applications are likely to be written in WPF.

Silverlight

  1. It is a tool for web applications.
  2. It requires a browser plugin.
  3. It competes with Flash, Java web apps, and a straight HTML-CSS-JS solutions
  4. Applications using Silverlight are going to also have HTLM5-CSS-JS solutions in future releases. Such as SharePoint and Powerview.
  5. Future versions of applications using Silverlight are likely to use HTML5-CSS-JS.

So as you see their purposes are quite different and the life of WPF is not tied to Silverlight.

Let’s look at when the support for each stops.

Silverlight 5 Support Lifecycle

Silverlight is listed on Microsoft’s site as being supported until 2021. This means that you probably should be concerned right now. There is a question as to whether Silverlight 6 will be released. For these reasons, people are thinking that Silverlight has an end of life in site.

Sometimes a product is so popular it lives on, sometimes it just goes away. While Silverlight became popular, it didn’t become popular enough. The effort to make it work on all the different platforms was too hard and never completed. By the time such an effort were to succeed, HTML5 will already be out there and working on every platform. The mistake Microsoft made was not making Silverlight a free open source solution. If they had, its adoption would have been far greater. It would likely work on every platform already, and it would have succeeded to replace Flash by 2010 and would be a viable option for those who don’t think HTML5 will be the solution everyone hopes. However, this did not happen. By 2021, Silverlight may just go away.

WPF Support LifeCycle

WPF’s life is tied to the life of Windows. See this quote:

Beginning with .NET 3.5 SP1, the .NET Framework is considered a Component of the Windows OS. Components follow the Support Lifecycle policy of their parent product or platform.[1]

So that statement alone should make you feel good about the life of WPF. WPF is a permanent part of the .NET Framework and will last as long as the Windows version it is released with. Windows 8 is supported until 2023 so WPF is supported at least until 2023 too. That is two years longer than Silverlight. However, does anyone believe that the next windows versions will not include .NET Framework? I expect .NET Framework to be a primary part of Windows releases for the next decade or more.

I expect that the version of Windows that releases after 2020 will have .NET Framework and WPF will be included.

WPF is also providing windows application developers with stable frameworks, such as MVP and MVVM, for enterprises to build their software.  Companies are still moving to WPF and they still should be because Microsoft is moving to WPF.

Conclusion

Say “Yes” to choosing WPF

If you are just deciding on a solution for a Windows application’s user interface, you should choose WPF.

If you are making product road map decisions and you are looking ahead a five years or even a decade and you want to know what user interface to use, you should use WPF.

WPF has just begun what is going to be a long life that could span decades. It should be your primary choice for feature rich desktop applications. Visual Studio 2012 and other new and recent applications will use WPF and many future versions of software will run WPF.

Say “For now” to choosing Silverlight

If you are just deciding on a solution for a web application’s user interface today, you wouldn’t go wrong choosing Silverlight. You can use it for now. Let’s face it. HTML5 isn’t here yet. It is still “coming” and how long will it continue to be “coming” before it gets here?

If you are making product road map decisions and you are looking ahead a five years or even a decade and you want to know what user interface to use, you should probably not choose Silverlight or at least have an option that if Silverlight 6 is not released to go with another option, such as HTML5-CSS-JS.

Silverlight is having a mid-life crisis and yes it may die when support ends in 2021. Silverlight attempted to solve the limitations with web applications. However, while it didn’t fall short in features, it fell short in not being cross-platform. HTML5 will replace Flash, not Silverlight. And yet Silverlight is still useful today in 2012 and will probably still be useful for years. It will live for almost a decade and is still a good solution to choose until HTML5 becomes mainstream and fully supported in every browser. If Microsoft released Silverlight 6 and extends its support (which many think will not happen) then it Silverlight will remain a positive choice for writing rapid business applications.

Using Expression Blend and Visual States for Image Swapping

For this example, lets think of a stop light during the traffic of your morning commute. There will be three images of a stop light. Each image will have either the red, yellow, or green light on.

Link: I used traffic light images from here: http://www.psdgraphics.com/psd-icons/traffic-lights-icon-psd

*** This can be done 100% in Expression Blend without using any code at all. ***

Note: This is for both Developers and Designers. It is for designers because they can do all of this without code. It is for Developers because they need to know to not go reinvent the wheel and spend their time writing code to do this.

Step 1 – Create a new WPF Application project

You can do this in either Visual Studio or Expression Blend. For this example, we will use Expression Blend 4.

  1. Open Expression Blend 4.
  2. Go to File | New Project.
  3. Choose WPF Application.
  4. Name the project and click OK.
    Note: I named this project SwitchImagesWithVisualStates.

Step 2 – Add Images to the WPF project

  1. Right-click on your project and choose Add new folder.
  2. Name the folder Images.
  3. Open your file system and copy or drag your images to this new folder in Expression Blend.
    Note: If you copy the images using the windows file system, you may have to add the files to the project.

Step 3 – Design the View

We are going to have a simple view for this example with the images on the left and buttons on the right.

  1. Open MainWindow.xaml.
  2. Add a column to the default Grid, so there are two columns.
  3. Make the columns 3* and 1*. This will make the left column 75% and the right column 25% of the Grid size.
  4. Add all thee images to the left column.
  5. Remove any margins, heights or widths, and vertical or horizontal alignments from the images.
    Note: This is important so the images are always in the same place.
    Note: This assumes that all three of your images are identically sized and properly placed.
  6. Name each Image: ImageRedLight, ImageYellowLight, ImageGreenLight.
  7. Add a StackPanel to the right column.
  8. Remove any margins, heights or widths, and vertical or horizontal alignments from the StackPanel.
  9. Click to select the StackPanel in the Objects and Timeline box.
  10. Add three buttons to the StackPanel in the right column.
  11. Remove any margins, heights or widths, and vertical or horizontal alignments from the buttons.
  12. Name each button: ButtonRedLight, ButtonYellowLight, ButtonGreenLight.
Your View should now look like this in the Expresion Blend designer.

Your Xaml should look like this:

<Window
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="SwitchImagesWithVisualStates.MainWindow"
	x:Name="Window"
	Title="MainWindow"
	Width="640" Height="480">
	<Grid x:Name="LayoutRoot">
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="3*"/>
			<ColumnDefinition Width="1*"/>
		</Grid.ColumnDefinitions>
		<Image Name="ImageRedLight" Source="Images/Red.png" />
		<Image Name="ImageYellowLight" Source="Images/Yellow.png" />
		<Image Name="ImageGreenLight" Source="Images/Green.png" />
		<StackPanel Grid.Column="1">
			<Button Name="ButtonRedLight" Content="Red Light"/>
			<Button Name="ButtonYellowLight" Content="Yellow Light"/>
			<Button Name="ButtonGreenLight" Content="Green Light"/>
		</StackPanel>
	</Grid>
</Window>

Step 4 – Add VisualStates in a VisualStateGroup

  1. In Expression Studio, click on the States tab.
    Note: Sometimes the States tab is hard to find.
  2. On the top right of the States tab, click icon that has a + sign to add a VisualStateGroup.
  3. Name the VisualStateGroup.
    Note: I named mine VisualStateGroupTrafficLights.
  4. Under the VisualStateGroup you now have another icon with a + sign (the Add state icon) that add a VisualState to the VisualStateGroup. Click it three times to add three VisualStates.
  5. Name the VisualStates: VisualStateRedLight, VisualStateYellowLight, VisualStateGreenLight.

Step 5 – Set new values for each VisualState

  1. Configure the VisualStateRedLight.
    1. Click on VisualStateRedLight.
    2. You will see a red outline around the designer and the words: VisualStateRedLight state recording is on.
    3. In the Objects and Timeline tab, press and hold control and click to select both ImageYellowLight and ImageGreenLight.
    4. Go to the Properties tab.
    5. Change the visibility of the images to Hidden.
  2. Configure the VisualStateYellowLight.
    1. Click on VisualStateYellowLight.
    2. You will see a red outline around the designer and the words: VisualStateYellowLight state recording is on.
    3. In the Objects and Timeline tab, press and hold control and click to select both ImageRedLight and ImageGreenLight.
    4. Go to the Properties tab.
    5. Change the visibility of the images to Hidden.
  3. Configure the VisualStateGreenLight.
    1. Click on VisualStateGreenLight.
    2. You will see a red outline around the designer and the words: VisualStateGreenLight state recording is on.
    3. In the Objects and Timeline tab, press and hold control and click to select both ImageRedLight and ImageYellowLight.
    4. Go to the Properties tab.
    5. Change the visibility of the images to Hidden.

Step 6 – Configure each Button to switch to a VisualState on click

  1. Configure ButtonRedLight.
    1. In Assets, search for GoToStateAction.
    2. Click and drag the GoToStateAction and drop it in the designer over the ButtonRedLight.
    3. Go to Properties.
    4. Name it GoToRedLightState.
    5. Set the StateName to VisualStateRedLight.
  2. Configure ButtonYellowLight.
    1. In Assets, search for GoToStateAction.
    2. Click and drag the GoToStateAction and drop it in the designer over the ButtonYellowLight.
    3. Go to Properties.
    4. Name it GoToYellowLightState.
    5. Set the StateName to VisualStateYellowLight.
  3. Configure ButtonGeenLight.
    1. In Assets, search for GoToStateAction.
    2. Click and drag the GoToStateAction and drop it in the designer over the ButtonGreenLight.
    3. Go to Properties.
    4. Name it GoToGreenLightState.
    5. Set the StateName to VisualStateGreenLight.

That is it. You have now written an application that switches the image.

Here is your final Xaml.

<Window
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
	xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
	x:Class="SwitchImagesWithVisualStates.MainWindow"
	x:Name="Window"
	Title="MainWindow"
	Width="640" Height="480">
	<Grid x:Name="LayoutRoot">
		<VisualStateManager.VisualStateGroups>
			<VisualStateGroup x:Name="VisualStateGroupTrafficLights">
				<VisualState x:Name="VisualStateRedLight">
					<Storyboard>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageYellowLight">
							<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
						</ObjectAnimationUsingKeyFrames>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageGreenLight">
							<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
						</ObjectAnimationUsingKeyFrames>
					</Storyboard>
				</VisualState>
				<VisualState x:Name="VisualStateYellowLight">
					<Storyboard>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageRedLight">
							<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
						</ObjectAnimationUsingKeyFrames>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageGreenLight">
							<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
						</ObjectAnimationUsingKeyFrames>
					</Storyboard>
				</VisualState>
				<VisualState x:Name="VisualStateGreenLight">
					<Storyboard>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageRedLight">
							<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
						</ObjectAnimationUsingKeyFrames>
						<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageYellowLight">
							<DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/>
						</ObjectAnimationUsingKeyFrames>
					</Storyboard>
				</VisualState>
			</VisualStateGroup>
		</VisualStateManager.VisualStateGroups>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="3*"/>
			<ColumnDefinition Width="1*"/>
		</Grid.ColumnDefinitions>
		<Image x:Name="ImageRedLight" Source="Images/Red.png" />
		<Image x:Name="ImageYellowLight" Source="Images/Yellow.png" />
		<Image x:Name="ImageGreenLight" Source="Images/Green.png" />
		<StackPanel Grid.Column="1">
			<Button x:Name="ButtonRedLight" Content="Red Light">
				<i:Interaction.Triggers>
					<i:EventTrigger EventName="Click">
						<ei:GoToStateAction x:Name="GoToRedLightState" StateName="VisualStateRedLight"/>
					</i:EventTrigger>
				</i:Interaction.Triggers>
			</Button>
			<Button x:Name="ButtonYellowLight" Content="Yellow Light">
				<i:Interaction.Triggers>
					<i:EventTrigger EventName="Click">
						<ei:GoToStateAction x:Name="GoToYellowLightState" StateName="VisualStateYellowLight"/>
					</i:EventTrigger>
				</i:Interaction.Triggers>
			</Button>
			<Button x:Name="ButtonGreenLight" Content="Green Light">
				<i:Interaction.Triggers>
					<i:EventTrigger EventName="Click">
						<ei:GoToStateAction x:Name="GoToGreenLightState" StateName="VisualStateGreenLight"/>
					</i:EventTrigger>
				</i:Interaction.Triggers>
			</Button>
		</StackPanel>
	</Grid>
</Window>

Notice there are additional dependencies added that come from System.Windows.Interactivity.dll:

  1. xmlns:i=”http://schemas.microsoft.com/expression/2010/interactivity”
  2. Mli>xmlns:ei=”http://schemas.microsoft.com/expression/2010/interactions”

There is a lot more to learn. We didn’t even touch Transition or Easing methods. We didn’t discuss how to hook this up into a full application, or possible an MVVM application.

Loading or Saving a XAML Resource Dictionary

Here is a rudimentary example of how to load a ResourceDictionary.xaml file and then how to change it and save the changes.

<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">
    <sys:String x:Key="HW">Hello, World</sys:String>
</ResourceDictionary>
using System;
using System.IO;
using System.Windows;
using System.Windows.Markup;

namespace ReadAndWriteToXaml
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public static ResourceDictionary Dictionary;
        public static String XamlFileName = "Dictionary1.xaml";

        public App()
        {
            LoadStyleDictionaryFromFile(XamlFileName);
        }

        /// <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
                        Dictionary = (ResourceDictionary)XamlReader.Load(fs);
                        // Clear any previous dictionaries loaded
                        Resources.MergedDictionaries.Clear();
                        // Add in newly loaded Resource Dictionary
                        Resources.MergedDictionaries.Add(Dictionary);
                    }
                }
                catch
                {
                    // Do something here if file not found
                }
            }
        }

        private void Application_Exit_1(object sender, ExitEventArgs e)
        {
            try
            {
                Dictionary["HW"] += "Hello, back!"; 
                StreamWriter writer = new StreamWriter(XamlFileName);
                XamlWriter.Save(Dictionary, writer);
            }
            catch
            {
                // Do something here if file not found
            }
        }
    }
}

Note: Unfortunately you cannot use two way mode when binding to DynamicResource objects, so editing the xaml file is made a bit more complex. But hopefully, this will help you get started.

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

How to avoid a blurry screen when using DropShadowEffects

Today, I created a DropShadowEffect on a Border. Any child of that border ended up being slightly blurry as well.

Well, it turns out that this is just the way it is. Child data of a Border will get blurry if a blur affects is applied to a Border.

The fix was somewhat easy. Make the border a sibling, not a parent.  What does this mean?  Look at the difference in the below XAML.

Border as Parent (Bad and Blurry)

<Window x:Class="RoundedCornerApp.RoundedCornerWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStartupLocation="CenterScreen"
        Title="Rounded Corner Window"            
        Height="690" Width="890" 
        Style="{DynamicResource RoundedCornerWindowStyle}">
    <Border x:Name="MainBorder" Style="{DynamicResource RoundedCornerMainBorderStyle}" >
        <Grid Name="MainGrid" Style="{DynamicResource RoundedCornerMainGridStyle}" >
        </Grid>
    </Border>
</Window>

Border as Sibling (Good and Clear)

<Window x:Class="RoundedCornerApp.RoundedCornerWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        WindowStartupLocation="CenterScreen"
        Title="Rounded Corner Window"            
        Height="690" Width="890" 
        Style="{DynamicResource RoundedCornerWindowStyle}">
    <Grid Style="{DynamicResource RoundedSiblingGridStyle}" MouseLeftButtonDown="DragWindow" >
        <Border x:Name="MainBorder" Style="{DynamicResource RoundedCornerMainBorderStyle}" />
        <Grid Name="MainGrid" Style="{DynamicResource RoundedCornerMainGridStyle}" >


        </Grid>
    </Grid>
</Window>

Notice that we first add a parent Grid, then we remove the child MainGrid from the MainBorder and put both the MainBorder and the MainGrid under the new parent Grid. This did take a little different styling, but it resolved the issue. I no longer have blurriness when using a DropShadowEffect on my border.

Here is my Style ResourceDictionary.

<ResourceDictionary
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <!-- Start - Rounded Corner Window Style -->
    <Style x:Key="RoundedCornerWindowStyle" TargetType="{x:Type Window}">
        <Setter Property="WindowStyle" Value="None" />
        <Setter Property="AllowsTransparency" Value="True" />
        <Setter Property="Background" Value="Transparent" />
    </Style>
    <!-- End - Rounded Corner Window Style -->

    <!-- Start - Sibling Grid Holder Style -->
    <Style x:Key="RoundedSiblingGridStyle" TargetType="{x:Type Grid}" BasedOn="{x:Null}" />
    <!-- Start - Sibling Grid Holder Style -->

    <!-- Start - Main Border Style -->
    <Style x:Key="RoundedCornerMainBorderStyle" TargetType="{x:Type Border}">
        <Setter Property="CornerRadius" Value="10" />
        <Setter Property="Margin" Value="0,0,10,10" />
        <Setter Property="Background" Value="#FF112DB7" />
        <Setter Property="BorderBrush" Value="Black" />
        <Setter Property="BorderThickness" Value="2" />
        <Setter Property="OpacityMask" Value="#FF223EC7"  />
        <!--Some apps looks fuzzy-->
        <Setter Property="Effect">
            <Setter.Value>
                <DropShadowEffect Color="Gray" Opacity=".50" ShadowDepth="10" />
            </Setter.Value>
        </Setter>
    </Style>
    <!-- End - Main Border Style -->

    <!-- Start - Main Grid Style -->
    <Style x:Key="RoundedCornerMainGridStyle" TargetType="{x:Type Grid}">
        <Setter Property="Margin" Value="10,10,20,20" />
    </Style>
    <!-- End - Main Grid Style -->
</ResourceDictionary>

WPF MenuItem as a RadioButton

It seems that there is not a MenuItem that works as a RadioButton that allows only a single selection that is in WPF. So I set off to figure out the best way to do this in WPF.

So let me go ahead and put the final solution right here on top. Then I will walk you through how I arrived at this solution. I researched a lot of solutions and none of them were this solution. I had to figure this one out myself  and I am glad I did because this one is the shortest and sweetest solution yet.

Here is a project showing how to do this with two examples, one directly in the MainWindow.xaml and one as its own class.

MenuItemWithRadioButtonExample.zip

Here is the code for creating a class that just works as a MenuItem with a RadioButton.

<MenuItem x:Class="MenuItemWithRadioButtonExample.MenuItemWithRadioButton"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Header="RadioButton Menu" >
    <MenuItem.Resources>
        <RadioButton x:Key="RadioButtonResource" x:Shared="false" HorizontalAlignment="Center"
                     GroupName="MenuItemRadio" IsHitTestVisible="False"/>
    </MenuItem.Resources>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Icon" Value="{DynamicResource RadioButtonResource}"/>
            <EventSetter Event="Click" Handler="MenuItemWithRadioButtons_Click" />
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

Then you need to add the MenuItemWithRadioButtons_Click event method to your code-behind as well.

private void MenuItemWithRadioButtons_Click(object sender, System.Windows.RoutedEventArgs e)
{
    MenuItem mi = sender as MenuItem;
    if (mi != null)
    {
        RadioButton rb = mi.Icon as RadioButton;
        if (rb != null)
        {
            rb.IsChecked = true;
        }
    }
}

Note: Since this even code involves the View only, this doesn’t break MVVM. With MVVM it is allowed to put code in the code-behind as long as it is code only for the View.

This works quite well and I am quite happy with it. Here is how it looks

Attempt 1 – A RadioButton in MenuItem.ItemsTemplate

Result = Failed!

I changed the MenuItem.ItemsTemplate, as follows.

<MenuItem.ItemTemplate>
    <DataTemplate>
        <RadioButton Content="{Binding}" GroupName="Group" />
    </DataTemplate>
</MenuItem.ItemTemplate>

This almost worked, but it wasn’t quite right. It turns out that anything in the DataTemplate is actually boxed inside a MenuItem, so it left a space. Look at this screen shot.

Notice there is a square space on the left, then a slight separator, then our RadioButton. We need the toggle to be in that empty box, and only the text to be on the right. Also clicking on the empty box doesn’t click the RadioButton.

So I need to figure out how to make it not be boxed in a MenuItem. It might be possible to find a way to make the DataTemplate not be boxed in a MenuItem, but I researched this and decided it wasn’t the best way to go.

Attempt 2 – A RadioButton in MenuItem.ItemContainerStyle

Result = Failed!

In my second attempt, I attempted to change the ItemContainerStyle.

<MenuItem.ItemContainerStyle>
    <Style TargetType="MenuItem">
        <Setter Property="Icon">
            <Setter.Value>
                <RadioButton HorizontalAlignment="Center" GroupName="MenuItemRadio" />
            </Setter.Value>
        </Setter>
    </Style>
</MenuItem.ItemContainerStyle>

This didn’t work either. Look at this screen shot.

It seems that only one instance of the RadioButton was created on so only the last item it was applied to actual showed it.

It had a second issue in that the RadioButton didn’t actually have any content. This might be a problem if you are hoping to use the Content in a click event. It seems that both MenuItem.Header and RadioButton.Content should be the same value, but only the MenuItem.Header should display.

The third issue was that the RadioButton is only toggled when clicking directly on the RadioButton, but not when clicking on the text or “Header” portion of the MenuItem.

The fourth issue is that when clicking the RadioButton the menu stays open even if StayOpenOnClick=”false” is set.

Attempt 3 – An unshared RadioButton in Resources used by MenuItem.ItemsTemplate (Success)

While it didn’t work the first time, this method had promise. Step two got me close, but left me with three problems to solve.

  1. I needed to figure out a way to not have the MenuItem elements share the RadioButton and that didn’t take long to research and resolve. I just needed to declare the RadioButton outside the Style and then use a StaticResource to bind to it.
  2. I needed to add an event to have the MenuItem click pass the click on to the RadioButton. That was easy enough.
  3. I needed to make it so the Menu would close when clicking directly on the RadioButton. I actually just set IsHitTestVisible=”false” on the RadioButton, because we already made just clicking the MenuItem work in problem 2.
  4. I had to change the RadioButton’s Horizontal Alignment to Center to make it look best.

So here is a screenshot so you can see it looks just how you want.

Check out the Xaml and event method as well as the example project at the top of this page.

Note: If you need to make the MenuItem.Header and RadioButton.Content share the same value, then do this:

<MenuItem x:Class="MenuItemWithRadioButtonExample.MenuItemWithRadioButton"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Header="RadioButton Menu" >
    <MenuItem.Resources>
        <RadioButton x:Key="RadioButtonResource" x:Shared="false" HorizontalAlignment="Center" 
                     GroupName="MenuItemRadio" IsHitTestVisible="False">
            <RadioButton.Content>
                <Label Content="{Binding Path=Header, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                       Visibility="Collapsed"/>
            </RadioButton.Content>
        </RadioButton>
    </MenuItem.Resources>
    <MenuItem.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Setter Property="Icon" Value="{DynamicResource RadioButtonResource}"/>
            <EventSetter Event="Click" Handler="MenuItemWithRadioButtons_Click" />
        </Style>
    </MenuItem.ItemContainerStyle>
</MenuItem>

Notice that Visibility=”Collapsed” is set, as we don’t need both the MenuItem.Header and the RadioButton.Content to display. I thought I needed this, but it turned out I didn’t. Still, I thought I would share it anyway.

XAML is Awesome!

Another test post that says XAML is awesome!