Archive

Posts Tagged ‘WPF’

Adding a WPF Settings Page To The Tools Options Dialog Window For Your Visual Studio Extension

April 25th, 2014 1 comment

I recently created my first Visual Studio extension, Diff All Files, which allows you to quickly compare the changes to all files in a TFS changeset, shelveset, or pending changes (Git support coming soon). One of the first challenges I faced when I started the project was where to display my extension’s settings to the user, and where to save them.  My first instinct was to create a new Menu item to launch a page with all of the settings to display, since the wizard you go through to create the project has an option to automatically add a new Menu item the Tools menu.  After some Googling though, I found the more acceptable solution is to create a new section within the Tools -> Options window for your extension, as this will also allow the user to import and export your extension’s settings.

Adding a grid or custom Windows Forms settings page

Luckily I found this Stack Overflow answer that shows a Visual Basic example of how to do this, and links to the MSDN page that also shows how to do this in C#.  The MSDN page is a great resource, and it shows you everything you need to create your settings page as either a Grid Page, or a Custom Page using Windows Forms (FYI: when it says to add a UserControl, it means a System.Windows.Forms.UserControl, not a System.Windows.Controls.UserControl).  My extension’s settings page needed to have buttons on it to perform some operations, which is something the Grid Page doesn’t support, so I had to make a Custom Page.  I first made it using Windows Forms as the page shows, but it quickly reminded me how out-dated Windows Forms is (no binding!), and my settings page would have to be a fixed width and height, rather than expanding to the size of the users Options dialog window, which I didn’t like.

Adding a custom WPF settings page

The steps to create a Custom WPF settings page are the same as for creating a Custom Windows Forms Page, except instead having your settings control inherit from System.Forms.DialogPage (steps 1 and 2 on that page), it needs to inherit from Microsoft.VisualStudio.Shell.UIElementDialogPage.  And when you create your User Control for the settings page’s UI, it will be a WPF System.Windows.Controls.UserControl.  Also, instead of overriding the Window method of the DialogPage class, you will override the Child method of the UIElementDialogPage class.

Here’s a sample of what the Settings class might look like:

using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;

namespace VS_DiffAllFiles.Settings
{
	[ClassInterface(ClassInterfaceType.AutoDual)]
	[Guid("1D9ECCF3-5D2F-4112-9B25-264596873DC9")]	// Special guid to tell it that this is a custom Options dialog page, not the built-in grid dialog page.
	public class DiffAllFilesSettings : UIElementDialogPage, INotifyPropertyChanged
	{
		#region Notify Property Changed
		/// <summary>
		/// Inherited event from INotifyPropertyChanged.
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>
		/// Fires the PropertyChanged event of INotifyPropertyChanged with the given property name.
		/// </summary>
		/// <param name="propertyName">The name of the property to fire the event against</param>
		public void NotifyPropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}
		#endregion

		/// <summary>
		/// Get / Set if new files being added to source control should be compared.
		/// </summary>
		public bool CompareNewFiles { get { return _compareNewFiles; } set { _compareNewFiles = value; NotifyPropertyChanged("CompareNewFiles"); } }
		private bool _compareNewFiles = false;

		#region Overridden Functions

		/// <summary>
		/// Gets the Windows Presentation Foundation (WPF) child element to be hosted inside the Options dialog page.
		/// </summary>
		/// <returns>The WPF child element.</returns>
		protected override System.Windows.UIElement Child
		{
			get { return new DiffAllFilesSettingsPageControl(this); }
		}

		/// <summary>
		/// Should be overridden to reset settings to their default values.
		/// </summary>
		public override void ResetSettings()
		{
			CompareNewFiles = false;
			base.ResetSettings();
		}

		#endregion
	}
}

 

And what the code-behind for the User Control might look like:

using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Navigation;

namespace VS_DiffAllFiles.Settings
{
	/// <summary>
	/// Interaction logic for DiffAllFilesSettingsPageControl.xaml
	/// </summary>
	public partial class DiffAllFilesSettingsPageControl : UserControl
	{
		/// <summary>
		/// A handle to the Settings instance that this control is bound to.
		/// </summary>
		private DiffAllFilesSettings _settings = null;

		public DiffAllFilesSettingsPageControl(DiffAllFilesSettings settings)
		{
			InitializeComponent();
			_settings = settings;
			this.DataContext = _settings;
		}

		private void btnRestoreDefaultSettings_Click(object sender, RoutedEventArgs e)
		{
			_settings.ResetSettings();
		}

		private void UserControl_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
		{
			// Find all TextBoxes in this control force the Text bindings to fire to make sure all changes have been saved.
			// This is required because if the user changes some text, then clicks on the Options Window's OK button, it closes 
			// the window before the TextBox's Text bindings fire, so the new value will not be saved.
			foreach (var textBox in DiffAllFilesHelper.FindVisualChildren<TextBox>(sender as UserControl))
			{
				var bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty);
				if (bindingExpression != null) bindingExpression.UpdateSource();
			}
		}
	}
}

 

And here’s the corresponding xaml for the UserControl:

<UserControl x:Class="VS_DiffAllFiles.Settings.DiffAllFilesSettingsPageControl"
						 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:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
						 xmlns:QC="clr-namespace:QuickConverter;assembly=QuickConverter"
						 mc:Ignorable="d" 
						 d:DesignHeight="350" d:DesignWidth="400" LostKeyboardFocus="UserControl_LostKeyboardFocus">
	<UserControl.Resources>
	</UserControl.Resources>

	<Grid>
		<StackPanel Orientation="Vertical">
			<CheckBox Content="Compare new files" IsChecked="{Binding Path=CompareNewFiles}" ToolTip="If files being added to source control should be compared." />
			<Button Content="Restore Default Settings" Click="btnRestoreDefaultSettings_Click" />
		</StackPanel>
	</Grid>
</UserControl>

You can see that I am binding the CheckBox directly to the CompareNewFiles property on the instance of my Settings class; yay, no messing around with Checked events 🙂

This is a complete, but very simple example. If you want a more detailed example that shows more controls, check out the source code for my Diff All Files extension.

A minor problem

One problem I found was that when using a TextBox on my Settings Page UserControl, if I edited text in a TextBox and then hit the OK button on the Options dialog to close the window, the new text would not actually get applied.  This was because the window would get closed before the TextBox bindings had a chance to fire; so if I instead clicked out of the TextBox before clicking the OK button, everything worked correctly.  I know you can change the binding’s UpdateSourceTrigger to PropertyChanged, but I perform some additional logic when some of my textbox text is changed, and I didn’t want that logic firing after every key press while the user typed in the TextBox.

To solve this problem I added a LostKeyboardFocus event to the UserControl, and in that event I find all TextBox controls on the UserControl and force their bindings to update.  You can see the code for this in the snippets above.  The one piece of code that’s not shown is the FindVisualChildren<TextBox> method, so here it is:

/// <summary>
/// Recursively finds the visual children of the given control.
/// </summary>
/// <typeparam name="T">The type of control to look for.</typeparam>
/// <param name="dependencyObject">The dependency object.</param>
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject dependencyObject) where T : DependencyObject
{
	if (dependencyObject != null)
	{
		for (int index = 0; index < VisualTreeHelper.GetChildrenCount(dependencyObject); index++)
		{
			DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, index);
			if (child != null &amp;&amp; child is T)
			{
				yield return (T)child;
			}

			foreach (T childOfChild in FindVisualChildren<T>(child))
			{
				yield return childOfChild;
			}
		}
	}
}

 

And that’s it.  Now you know how to make a nice Settings Page for your Visual Studio extension using WPF, instead of the archaic Windows Forms.

Happy coding!

Don’t Write WPF Converters; Write C# Inline In Your XAML Instead Using QuickConverter

December 13th, 2013 7 comments

If you’ve used binding at all in WPF then you more then likely have also written a converter.  There are lots of tutorials on creating converters, so I’m not going to discuss that in length here.  Instead I want to spread the word about a little known gem called QuickConverter.  QuickConverter is awesome because it allows you to write C# code directly in your XAML; this means no need for creating an explicit converter class.  And it’s available on NuGet so it’s a snap to get it into your project.

 

A simple inverse boolean converter example

As a simple example, let’s do an inverse boolean converter; something that is so basic I’m surprised that it is still not included out of the box with Visual Studio (and why packages like WPF Converters exist).  So basically if the property we are binding to is true, we want it to return false, and if it’s false, we want it to return true.

The traditional approach

This post shows the code for how you would traditionally accomplish this.  Basically you:

1) add a new file to your project to hold your new converter class,

2) have the class implement IValueConverter,

3) add the class as a resource in your xaml file, and then finally

4) use it in the Converter property of the xaml control.  Man, that is a lot of work to flip a bit!

Just for reference, this is what step 4 might look like in the xaml:

<CheckBox IsEnabled="{Binding Path=ViewModel.SomeBooleanProperty, Converter={StaticResource InverseBooleanConverter}" />

 

Using QuickConverter

This is what you would do using QuickConverter:

<CheckBox IsEnabled="{qc:Binding '!$P', P={Binding Path=ViewModel.SomeBooleanProperty}}" />

That it! 1 step! How freaking cool is that!  Basically we bind our SomeBooleanProperty to the variable $P, and then write our C# expressions against $P, all in xaml! This also allows us to skip steps 1, 2, and 3 of the traditional approach, allowing you to get more done.

 

More examples using QuickConverter

The QuickConverter documentation page shows many more examples, such as a Visibility converter:

Visibility="{qc:Binding '$P ? Visibility.Visible : Visibility.Collapsed', P={Binding ShowElement}}"

 

Doing a null check:

IsEnabled="{qc:Binding '$P != null', P={Binding Path=SomeProperty}"

 

Checking a class instance’s property values:

IsEnabled="{qc:Binding '$P.IsValid || $P.ForceAlways', P={Binding Path=SomeClassInstance}"

 

Doing two-way binding:

Height="{qc:Binding '$P * 10', ConvertBack='$value * 0.1', P={Binding TestWidth, Mode=TwoWay}}"

 

Doing Multi-binding:

Angle="{qc:MultiBinding 'Math.Atan2($P0, $P1) * 180 / 3.14159', P0={Binding ActualHeight, ElementName=rootElement}, P1={Binding ActualWidth, ElementName=rootElement}}"

 

Declaring and using local variables in your converter expression:

IsEnabled="{qc:Binding '(Loc = $P.Value, A = $P.Show) => $Loc != null &amp;&amp; $A', P={Binding Obj}}"

* Note that the "&&" operator must be written as "&amp;&amp;" in XML.

 

And there is even limited support for using lambdas, which allows LINQ to be used:

ItemsSource="{qc:Binding '$P.Where(( (int)i ) => (bool)($i % 2 == 0))', P={Binding Source}}"

 

Quick Converter Setup

As mentioned above, Quick Converter is available via NuGet.  Once you have it installed in your project, there are 2 things you need to do:

1. Register assemblies for the types that you plan to use in your quick converters

For example, if you want to use the Visibility converter shown above, you need to register the System.Windows assembly, since that is where the System.Windows.Visibility enum being referenced lives.  You can register the System.Windows assembly with QuickConverter using this line:

QuickConverter.EquationTokenizer.AddNamespace(typeof(System.Windows.Visibility));

In order to avoid a XamlParseException at run-time, this line needs to be executed before the quick converter executes.  To make this easy, I just register all of the assemblies with QuickConverter in my application’s constructor.  That way I know they have been registered before any quick converter expressions are evaluated.

So my App.xaml.cs file contains this:

public partial class App : Application
{
	public App() : base()
	{
		// Setup Quick Converter.
		QuickConverter.EquationTokenizer.AddNamespace(typeof(object));
		QuickConverter.EquationTokenizer.AddNamespace(typeof(System.Windows.Visibility));
	}
}

Here I also registered the System assembly (using “typeof(object)”) in order to make the primitive types (like bool) available.

 

2. Add the QuickConverter namespace to your Xaml files

As with all controls in xaml, before you can use a you a control you must create a reference to the namespace that the control is in.  So to be able to access and use QuickConverter in your xaml file, you must include it’s namespace, which can be done using:

xmlns:qc="clr-namespace:QuickConverter;assembly=QuickConverter"

 

So should I go delete all my existing converters?

As crazy awesome as QuickConverter is, it’s not a complete replacement for converters.  Here are a few scenarios where you would likely want to stick with traditional converters:

1. You need some very complex logic that is simply easier to write using a traditional converter.  For example, we have some converters that access our application cache and lock resources and do a lot of other logic, where it would be tough (impossible?) to write all of that logic inline with QuickConverter.  Also, by writing it using the traditional approach you get things like VS intellisense and compile-time error checking.

2. If the converter logic that you are writing is very complex, you may want it enclosed in a converter class to make it more easily reusable; this allows for a single reusable object and avoids copy-pasting complex logic all over the place.  Perhaps the first time you write it you might do it as a QuickConverter, but if you find yourself copy-pasting that complex logic a lot, move it into a traditional converter.

3. If you need to debug your converter, that can’t be done with QuickConverter (yet?).

 

Summary

So QuickConverter is super useful and can help speed up development time by allowing most, if not all, of your converters to be written inline.  In my experience 95% of converters are doing very simple things (null checks, to strings, adapting one value type to another, etc.), which are easy to implement inline.  This means fewer files and classes cluttering up your projects.  If you need to do complex logic or debug your converters though, then you may want to use traditional converters for those few cases.

So, writing C# inline in your xaml; how cool is that!  I can’t believe Microsoft didn’t think of and implement this.  One of the hardest things to believe is that Johannes Moersch came up with this idea and implemented it while on a co-op work term in my office!  A CO-OP STUDENT WROTE QUICKCONVERTER!  Obviously Johannes is a very smart guy, and he’s no longer a co-op student; he’ll be finishing up his bachelor’s degree in the coming months.

I hope you find QuickConverter as helpful as I have, and if you have any suggestions for improvements, be sure to leave Johannes a comment on the CodePlex page.

Happy coding!

Categories: C#, WPF, XAML Tags: , , , , , , ,

Adding ValueChanged events to Dependency Objects in WPF

April 17th, 2011 No comments

You may be wondering which is the best way to hookup a DependencyProperty’s Callback event handler to handle Value Changed events.  The two methods to consider are:

Method 1 – Use static event hanlders, like so:

public virtual int SelectedID
{
	get { return (int)GetValue(SelectedIDProperty); }
	set { SetValue(SelectedIDProperty, value); }
}

public static readonly DependencyProperty SelectedIDProperty =
	DependencyProperty.Register("SelectedID", typeof(int), typeof(SelectorBase), 
                new PropertyMetadata(0, new PropertyChangedCallback(OnSelectedIDChanged)));

private static void OnSelectedIDChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
	// Perform event handler logic
}

 

Method 2 – Hookup event handler at initialize, and remove it during Dispose(), like so:

// Constructor
public SelectorBase()
{
	HookupEventHandlers();
}

private void HookupEventHandlers()
{
	TypeDescriptor.GetProperties(this)["SelectedID"].AddValueChanged(this, SelectedID_ValueChanged);
}

private void RemoveEventHandlers()
{
	TypeDescriptor.GetProperties(this)["SelectedID"].RemoveValueChanged(this, SelectedID_ValueChanged);
}

protected override void Dispose(bool isDisposing)
{
	base.Dispose(isDisposing);
	// If managed resources should be released
	if (isDisposing)
	{
		RemoveEventHandlers();
	}
}

public virtual int SelectedID
{
	get { return (int)GetValue(SelectedIDProperty); }
	set { SetValue(SelectedIDProperty, value); }
}

public static readonly DependencyProperty SelectedIDProperty =
	DependencyProperty.Register("SelectedID", typeof(int), typeof(SelectorBase), new PropertyMetadata(0));

private void SelectedID_ValueChanged(object sender, EventArgs e)
{
	// Perform event handler logic
}

So the advantage to using method 1 is that we have access to the property’s old and new values, we don’t have to worry about memory leaks (since the event handler is static), and if we create 100 instances of the control we still only have one static event handler in memory, instead of 100 local ones.  The disadvantage to method 1 is that these event handlers are going to exist in memory for the entire lifetime of the app, even if the view/control they are on is never referenced.

The advantage to using method 2 is that the event handlers only exist in memory if the view/control they are on is actually open.  The disadvantage is that we don’t have access to the property’s old value, and the developer has to remember to properly unhook the event in order to avoid a memory leak.

So method 1 is best suited to items that are used in many places (such as custom controls that may be plastered all of the place), while method 2 is best suited for views where there is likely to never be more than a few instances open at any given time, or in places that may not be accessed at all (e.g. a settings menu that is rarely accessed).

My WPF Binding won’t work. WTF!

April 17th, 2011 No comments

At one point or another I’m sure we’ve all been confused as to why our binding won’t work.  Here’s a couple things to keep in mind:

– have you set the DataContext to be the class containing the property you are binding to?  This can be done in XAML or in the code-behind.  For example, put "this.DataContext = this" in the code-behind file’s constructor.

– is the property you’re binding to public?  Also, it must be a property (with get; set; accessors), not a field (i.e. class variable).

– if you are using two way binding, do you have both a Get and Set accessor on the propery?

– if you are trying to set bindings on a usercontrol that you are placing on your form, you may have to set the DataContext in that control, or reference the property dynamically using something like:

<controls:CashCalculator

  CanModifyAmount="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:WpfViewBase}},

Path=CashOutViewModel.CanModifyAmount, Mode=OneWay}"

  CashDetail="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:WpfViewBase}},

Path=CashOutViewModel.CashOutModel.CashOut.CashDetail, Mode=OneWay}"/>

If you still don’t know why your binding isn’t working, be sure to check the Output window in Visual Studio while debugging, as it will display any binding errors that occur and (hopefully) give you more information about the problem.  You can also change the level of verbosity that is displayed for Binding errors, so if you aren’t getting enough information, in Visual Studio go into Tools -> Options -> Debugging -> Output Window and make sure Data Binding is at least set to Warning.

If changes made to the UI propogate to the code-behind, but changes made in the code-behind don’t propogate to the UI, you will either need to use the INotifyPropertyChanged pattern, or implement your code-behind properties as DependencyProperties, in order to let the UI know that the value has been updated and show the change.

Categories: Binding, WPF Tags: , , ,

Setting focus to an element in WPF

April 17th, 2011 No comments

So if you are trying to set focus to a WPF element, but are unable to.  Here is a quick checklist to go through:

– is the control you are trying to set focus to Enabled, Visible, Loaded, and Focusable.  If any of these properties are false, you cannot set focus to the element.

If you are using Binding to set these properties, make sure the binding is firing before you are trying to set the focus.

– does the control that already has focus allow focus to be taken away? If the control that currently has focus overrides the PreviewLostFocus event, it can set e.Handled to true to prevent other controls from stealing focus from it.

If all of these conditions seem to be met, but you still cannot seem to set the focus to a control, is another operation moving focus from your control to another control after you set focus to your control?  From a dispatcher perhaps?

Using the tool Snoop is great for viewing what control in your WPF application has focus, and is very useful in debugging for seeing what controls are recieving focus.  Once you know what control is getting focus instead of your control, you can put a breakpoint in the control’s GotFocus event to debug and see when focus is being moved to the control, and what fuction is performing the operation to move the focus.

Categories: WPF Tags: , , , ,