| Caleb's profileCaleb's RamblingsBlogLists | Help |
|
February 18 WPF RoutedCommands not routing correctly in a ContextMenuI recently ran into a few problems with RoutedCommands in a ContextMenu I was adding to an application. The problem was that when the ContextMenu was opened it wasn’t always finding the command bindings that I had in the parent Window (it would sometimes) and so the MenuItem was disabled. After searching the web for some answers I found a few people that had also noticed this problem and they had a proposed work around. You can find the work around here. However the work around provided didn’t fit well with how I was setting up the ContextMenu so I decided to dig a little deeper. After about 8 hours I found the reason and a solution to the problem that is far easier (at least for me) to put in place. Before we go too far though I’ll provide some code so that you can replicate the issue for your self. If you start with a blank WPF application project called RoutedCommandInContextMenu then you can simply add the following code to the listed files. Add to Window1.xaml <Window x:Class="RoutedCommandInContextMenu.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:RoutedCommandInContextMenu" Title="Window1" Height="300" Width="300"> <ScrollViewer> <TextBlock Text="fooooobaaaaaar"> <TextBlock.ContextMenu> <ContextMenu> <MenuItem Header="Foo" Command="{x:Static local:MyCommands.FooBar}" /> </ContextMenu> </TextBlock.ContextMenu> </TextBlock> </ScrollViewer> </Window> Add to Window1.cs /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); CommandBindings.Add(new CommandBinding(MyCommands.FooBar, FooExecuted, CanFooExecute)); } public void FooExecuted(object sender, ExecutedRoutedEventArgs e) { MessageBox.Show("Foo!"); } public void CanFooExecute(object sender, CanExecuteRoutedEventArgs e) { e.CanExecute = true; } } public static class MyCommands { public static RoutedCommand FooBar = new RoutedCommand(); } If you then run this application and right click (without doing anything else first) you will see that the “Foo” menu item is disabled in the context menu. You will also note that if you left click the non border area of the window and then right click again the “Foo” menu item is enabled. When I first noticed this behaviour I thought that perhaps the MenuItem was simply not calling the CanExecute method of the command. So I made a simple WrappedCommand class that implemented ICommand and used that as the command instead. I was then able to put a break in the can execute method of my wrapped command and see that it was indeed being called. I could also see that the underlying routed command was returning false for its CanExecute even though the Window’s command binding was never being called. Clearly there is something going on with the routing of the command. ContextMenus are implemented as a separate window which is managed by the Popup class. Because of this they have a different Visual Tree. Their Logical Tree is also separate from the Window they were launched from. There are one or two situations where it looks like the Popup might report itself to be a child of the launching Window, but it doesn’t in the case of our ContextMenu (even when it is working in our example). It turns out that in when a UIElement is determining if a routed command can execute or not it uses an internal method on the CommandManager class called OnCanExecute. In here we can see (with enough analasis) that the method searches for a command binding within the focus scope of the sender (the element that raised the event), then if it can’t find one it will transfer the event to the parent focus scope (assuming there is one) to see if it has any CommandBindings registered. This is how the routed command execution travels from the ContextMenu to the Window when things are working. The thing is that it will start routing the event in the parent scope from whatever has the logical focus in that scope, this is where our problem lies. Until we click the window (actually the ScrollViewer to be precise) the current logical focus is null, which means that the CommandManager doesn’t know where to start routing the event in the parent focus scope so it doesn’t transfer the event. Once we click the ScrollViewer the logical focus scope is set to the ScrollViewer so the CommandManager transfers execution of the routed event to the scroll viewer which then finds the Window’s command bindings and everything is dandy. To fix this issue you can simply add a call to Focus() in the Window’s constructor like so:
I believe that this is a bug in the framework as the documentation on Logical Focus states the following:
You can demonstrate that this statement in the documentation is correct by adding the following code to the Window1 class and commenting out the Focus() call in the constructor.
Now when you right click the window the assertion will fail, because FocusManager.GetFocusedElement() is returning null, but the Keyboard is saying that the Window has the focus. So there you go, after a lot of stepping through framework code, pulling my hair out and staying up into the wee hours of the morning, I was finally able to figure out what was going on. I have raised this as a bug on MS connect so if you would like to rate it that might be nice. The bug can be found here: https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=415864&SiteID=212. Also when writing this post I found the following article on WPF command routing which explains a few other interesting uses for focus scopes which I found interesting: http://www.aspfree.com/c/a/.NET/More-on-Commands-Input-and-the-WPF/2/ February 09 How to set a binding on a DependencyObject from code.
Sometimes it is useful to be able to set bindings on DependencyObjects in code. If the object you are working in derives from FrameworkElement you can just use the object’s SetBinding method, but what if the object is derived from something else such as a Freezable? The answer is that you use the static BindingOperations classes' SetBinding method, which unsurprisingly is what the implementation of SetBinding on FrameworkElement calls to do its work anyway. February 04 Scratch Pad projects are a great idea.
For that last half a year or so I have been using a solution that I call scratch pad to try out ideas. For example if I have an idea for some sort of crazy layout panel that I want to try out, but don’t wont to mess around with the project that it is destined for, then I make a new project (or reuse an existing one) in my ScratchPad.sln and try out the idea. This has worked really well for me, because I typically find it hard to decide on the best way to do something to start with which makes me procrastinate doing it. Since the scratch pad doesn’t matter and I don’t have to worry about making a mess it is much easier for me to just jump in and try something out. February 02 WPF Designer Frustrations
Lately I have been increasingly frustrated with the designers for WPF. I would not be at all surprised to find that I would have some of the same frustrations with the Windows forms designer, but some of the frustrations are more WPF specific. The real problem seems to be that as soon as you do something non trivial the designer will break even though the code runs perfectly fine. Here are some of the things that are giving me grief at the moment.
The designers are very useful when they are working as they enable you to quickly try out loads of different brushes for styles without having to start the app up each time, but increasingly I find my self fighting with the designer to get it to show me the thing I am interested in so I can work on it. Maybe I am using the wrong approach to things, but there seems very little documentation of a better way to work with them while actually showing the data you are interested in. What would be truly awesome is if you could attach a designer program to a running application and muck around with the properties of the objects while the application was running. That way you wouldn’t have the problem of not being able to see the working data from the database or some other datasource. February 01 How To find the config file path for you application.
Today I was trying to solve an issue with nunit not setting the correct path for the assembly I was testing’s config file. Well it wasn’t setting the expected path anyway. It took me a little while to find out where the application was looking for the config file. Eventually I discovered the following property: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile. Hopefully this can be of some use to you in the future. January 28 Generating Linq expressions in foreach loops.I had an interesting problem today. I was running through a foreach loop and generating a linq query with a predicate based on the element I was currently at. Something a little like this:
Of course the example doesn’t compile and the names have been messed with but you get the idea. Anyway a problem arose because the query hadn’t actually been run yet. So when it did come time to run the query all of the results were the same because only the final value of the sm variable was used. To get around the problem you can either get the count before moving onto the next one, or if you do want the deferred execution you can just make a separate method that does the work. Something like this: void doSomething() { foreach (var sm in new SMRepository()) { AddGroup(sm); } } private void AddGroup(SM sm) { var bgvm = new GroupViewModel(this) { Descriptor = sm, Date = DateTime.Today }; var gb = _workingBSet.Where(b => b.SM == sm); bgvm.B = gb; Groups.Add(bgvm); }This avoids the problem because the same local variable is not captured by the closure (which is created by the lambda expression). I hope this proves useful to someone. January 12 How to get a reference to the AdornerLayer when working with a custom controlToday I was working on a custom control that needed to add something to the adorner layer as soon as it was created. You can’t get it in the constructor, because the control isn’t in the visual tree yet. The place I ended up deciding to get it was in the OnVisualParentChanged method. There may be a better place, but this seems to work fine. August 18 Loading an image file as an ImageSource from code.I was recently trying to load an image file in a WPF project. I wanted to load the image file as an ImageSource so I could access its metadata. I needed a class to wrap the ImageSource so that the class could provide easy access through properties to some metadata values you must use a specific query to access. Then the wrapped class could be used in an items control with a DataTemplate that could display both the image and the metadata for that image. Unfortunately it took a little while to find the best way to load the image and still have the metadata available. You can use the BitmapImage class to load the image easily with just the file path, but then the metadata is not available. You could also use the approach used in the BitmapMetadata Sample the problem there is that they already know what type of image they are loading so they can instantiate the appropriate encoder easily. It also seems like a fair bit of work when in the XAML file all you have to do to set a property of type ImageSource is type in the URI. Of course it is possible to do pretty much the same thing, but I couldn't seem to find anything about in in the MSDN docs (the secret is there, but there aren't any examples of it being used). Because all values in XAML files are represented as strings they must be converted to the type they are meant to be before they are used. For example if you set the width property of a Window in a XAML file it must convert the string "1" to the actual integer value 1. Now it turns out that the String type implements IConvertible which is how most of these conversions takes place. However before using the IConvertible interface the XAML loader searches the required type of a property for the TypeConverterAttribute. This attribute basically provides the type name of a class which inherits from TypeConverter. I then looked up the documentation for ImageSource and saw that the TypeConverter used is of type ImageSourceConverter</A ImageSourceConverter imgSrcConverter = new ImageSourceConverter(); Bitmap = imgSrcConverter.ConvertFromString(imageUri) as ImageSource;
August 05 20th Anniversary Wild Winter Weekend Tube raceLiveJournal Tags: Snow,Wild Winter Weekend,Tubes
This past weekend (2nd and 3rd of August) was the weekend of the CocaCola Wild Winter Weekend. Along with a number of other events there was an inner tube race down the centre of the half pipe. My brother Josh and I went in the race. The rules are pretty simple.
To make it a bit more interesting a number of small jumps are setup in the middle of the half pipe. This means you might get anything up to half a meter of air which makes staying on the tube a little difficult. Things normally get pretty hectic as other teams crash in front of you and inevitably you ram into them. Five teams race down the centre of the pipe at once and only the top two make it through to the next round. There were three rounds in total with the winner of the third round being the overall winner. As well as the overall race winners there was also a prize for the best fancy dress. Josh and I went dressed as a Wookie (think Chubaka from Star Wars, thanks to Ed and Sam for that costume) and the Cookie Monster from Sesame Street (thanks to Gary and Jayne for that one). The judges couldn't end up deciding which team had the best fancy dress so they split it between four teams including us. The three other teams that shared in the prize were dressed as the following:
Unfortunately Josh and I were knocked out of the race in the first round. We came in third, but we both think that it should have been second. The team in front of us didn't look like they were both on the tube as it crossed the line, at least not from our perspective. The race will be shown on Channel 9 sometime on the 31st of August so we are keen to see a replay to see if we really were jipped or not. Unfortunately we were a little rushed getting into our costumes and running over to the half pipe for the competition (even though it ended up being a lot later than we were running) so we didn't manage to take any photos of the event. So if you want to see what it was like you will have to wait for the TV coverage. Until then you can check out these videos of the tube race from 2000 on YouTube so you can get a feel for the action. Video 1 & Video 2 June 25 I bought my self a new snowboard!I bought a new snowboard on Monday from Adrenalin Plus. All up the gear cost $1,770 with a 15% discount. I was going to go with a Burton Air, but the chap in the shop convinced me that a Ride Havoc was a better deal. I got Forum boots and bindings. The boots were the most comfortable ones in the shop. Here are some pics. June 24 Blend Error: "The imported project "C:\Microsoft.CSharp.targets" was not found.This morning I was creating a new WPF project in Visual Studio 2008. I then tried to open that new project in Expression Blend (version 1) only to be greeted with an error message saying "The imported project "C:\Microsoft.CSharp.targets". I had had this problem before, but I couldn't remember how I fixed it. I did a quick Google and nothing came up so I thought I would write a blog post about it both for my own reference and for anyone else that has the same problem. The solutions for me was to open the project file in notepad and then edit the following line: <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> So that it reads like this: <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> The only difference is which variable it is using for the path. January 24 Using Inheriting Dependency Properties
Dependency property value inheritance is a very cool features in WPF. I recently came across a situation where I wanted to take advantage of an inheriting dependency property, but I had difficulty finding out exactly how to do what I wanted. I eventually found this article about Property Value Inheritance which gave me the answer I needed. The problem I had was that I wasn't using an attached property. I didn't think I needed to do this, because even though I wanted the inheritance to work over two different types of Control I was using the AddOwner method on the original DependencyProperty for my second Control. However inheritance doesn't work properly in any situation unless it is an attached property. This wasn't immediately apparent, I had been looking at the FrameworkPropertyMetadataOptions enumeration documentation and it didn't mention anything other than "The values of this dependency property are inherited by child elements" for the Inherits value. The documentation for WPF is actually quite good, but sometimes it isn't easy to figure out where to look. The most useful place to start looking for most things seems to be in the WPF Fundamentals page. To give you an example of why Dependency property value inheritance is a cool feature picture the following situation. You have an Appointment that contains multiple Bookings. A Booking represents a period of time where a resource is unavailable. Resources could be a staff members or rooms. You decide to have an AppointmentControl that contains multiple BookingControls. The AppointmentControl knows which Appointment its for and the BookingControl knows which Booking its for. However the Booking class doesn't have a reference back to its Appointment because it is burdensome to maintain references both ways. Now imagine that your booking control needs to know which Appointment the booking is for. Normally you would have to manually set an Appointment property on each BookingControl as it was added and unset it when it was removed, but in WPF you can just make the AppointmentControl's Appointment property an attached inheriting dependency property and then there is no extra work required. This is just one of the many scenarios where dependency property value inheritance is very useful. January 21 Use Tab to navigate AutoComplete on VistaOne of the things that has bugged me since moving to Windows Vista is that I was unable to find a way to use tab to navigate auto complete (in places such as windows explorer or the run dialog box). I used to turn this option on under Windows XP by using the TweakUI power toy. I tried googling for a way to turn this option on, but I was unable to find anything. So in search of the answer I turned to the Sysinternals Process Monitor. Using the process monitor I was able to determine which registry key the TweakUI tool changes and make this change on XP and then try the same key on Vista. After making the change and rebooting the auto complete behaved how I wanted it to. The following is a list of steps that I took to find the registry key and set it. You could use the same steps to find any registry key that is set by TweakUI or any other tool that modifies the registry. If you are only interested in this one setting and not the technique used to find it then skip to the end of step 4. NOTE: I recommend that you backup the registry (a system restore point does this) before you modify it
September 20 Creating a Customer InputGesture for Mouse Wheel Movements
I was working on an application today where I wanted to setup RoutedCommand that was executed when the user rolled the mouse wheel up. I also had another RoutedCommand that I wanted to be executed when the mouse wheel was rolled down. No problem right? I should just be able to add a MouseGesture to the RoutedCommand's InputGestures collection. However this isn't the case as their is no MouseAction that differentiates between mouse wheel directions. There is a MouseWheelClick action that matches when the mouse wheel is moved in any direction. This seemed a bit strange as I was sure it was something people would want to do fairly frequently. I did a quick google and found a number of other people that had the same problem. The solution that had been suggested to them was to just handle the appropriate mouse events and then manually call the command. I was unhappy with this solution as it kind of defeats the purpose of commands in the first place. It is also no where near as neat as it requires extra code that could have been more simply defined in XAML rather than code. So I decided to see if I could create a class that extended MouseGesture that allowed me to create the desired binding. After a little investigation I discovered that InputGestures have a Matches method that determines if input that has just occurred matches the gesture. The method has the following signature. public virtual bool Matches(object targetElement, InputEventArgs inputEventArgs) I then discovered that when the mouse wheel is moved the InputEventArgs that are passed in are an instance of MouseWheelEventArgs. MouseWheelEventArgs exposes a property called Delta which gives you amount that the mouse wheel has moved. Positive values in the Delta property mean that the mouse wheel was rolled up and negative values mean that it was scrolled down. Armed with this information I set out to make a new class called MouseWheelGesture which looks is shown below. public class MouseWheelGesture : MouseGesture { private MouseWheelAction mouseWheelAction; public MouseWheelAction MouseWheelAction { get { return mouseWheelAction; } set { mouseWheelAction = value; } } public MouseWheelGesture() : base(MouseAction.WheelClick) { mouseWheelAction = MouseWheelAction.AllMovement; } public override bool Matches(object targetElement, InputEventArgs inputEventArgs) { if (base.Matches(targetElement, inputEventArgs)) { MouseWheelEventArgs wheelArgs = inputEventArgs as MouseWheelEventArgs; if (wheelArgs != null) { if (MouseWheelAction == MouseWheelAction.AllMovement ||(MouseWheelAction == MouseWheelAction.WheelDown && wheelArgs.Delta < 0) || MouseWheelAction == MouseWheelAction.WheelUp && wheelArgs.Delta > 0) { return true; } } } return false; } } And here is the definition of the MouseWheelAction enum. public enum MouseWheelAction { AllMovement, WheelUp, WheelDown } So there you have it. I now have a new type of InputGesture that provides the required functionality in a way that can be easily setup in both code and XAML. If at this point if your wondering what commands are in WPF and how they are set up there is a good overview of them on msdn called Commanding Overview |
|
|