How to handle keypress in WPF using MVVM?

Did you want to capture the Enter key on a textbox, or the F3 key for find again in your WPF Application when you are using MVVM?

I was using custom behaviors for a while until I realized I was overcomplicating things far too much.

You can wire up commands right to keys very easily.

Here is a sample. Same concept for any framework control.

[sourcecode language=”csharp”]
<Window.InputBindings>
<KeyBinding Command="{Binding FindNextCommand}" Key="F3"/>
</Window.InputBindings>
[/sourcecode]

If you had a textbox, just set the TextBox.InputBindings and the key to Enter. Happy Coding!

Death by icon: Memory Leak in WPF Using MVVM and ImageSource

I was running a memory profile on our client application and kept seeing views being stuck in memory. It was odd since we freed them and there weren’t any discernable links that should be keeping them alive.

Well, that is until I saw that a GC Root object holding a reference at the top of the chain was an icon. An Icon. It was holding together a massive view and all the data, controls and containers that go with it. The memory would increase by 5-10 megs each time you went and left the view.

So, my next step was to figure out how in the world this icon was holding the view in memory. Where was the reference? The only usage was a simple binding to show the icon for particular types of nodes in our treeview.

I remembered from an earlier performance run that WPF has Freezable objects. WPF monitors these objects for changes. Well, that sounds like it uses an event. I doubt it polls.

I was right. There is an event on the image source. Apparently WPF latches on to that bad boy, and voila. You have a valid reference to the icon that the GC see as needed.

Why needed, well, to save cycles, we use a static instantiation of the bitmap. Loading from resources is expensive, so we use a readonly static. It never goes anywhere, therefore anything bound to its events doesn’t go anywhere.

So, what is the fix? I don’t want to stop using my static, as now I introduce a performance penalty. I can’t stop using the icon, then the user would be perturbed.

What to do?

Well, bring out your ice ray gun, because the solution is to Freeze the image. I mentioned earlier that WPF has Freezable objects. Well, if you Freeze it, then WPF doesn’t bind to the event since the object can’t change. So, a few lines of code later and we have a memory leak disaster averted.

Here was the old way:

[csharp]
private static readonly ImageSource MyIcon = new BitmapImage(new Uri("pack://application:,,,/Seekford.Client.Resources;component/Images/Icon.png")); 
[/csharp]

Here is the new way:

[csharp]
   private static readonly ImageSource MyIcon;
        static MyTreeModel()
        {
            MyIcon = new BitmapImage(new Uri("pack://application:,,,/Seekford.Client.Resources;component/Images/Icon.png"));        
            PARRiskIcon.Freeze();           
        }
[/csharp]

Simple, right. Yeah, if you know what to look for in the first place Smile

 

Happy coding!

Mouse Double Click for WPF in MVVM using a clean Behavior with Command Binding

I wanted to capture the double click event, which is actually the MouseLeftButtonDown with the e.ClickCount ==2.

Since I transitioned to a new WPF project, handed off the Silverlight work, I have been trying to keep the same MVVM pattern. I wanted to get the double click off of my TreeViewItem so the child node could invoke the ViewModel to execute a Command.

Here is the behavior I wrote to handle this simple task.

Snippet

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Controls;

namespace Seekford.Behaviors
{
    public static class MouseDoubleClickBehavior
    {
        /// <summary>
        /// Hooks up a weak event against the source Selectors MouseDoubleClick
        /// if the Selector has asked for the HandleDoubleClick to be handled
        ///�
        /// If the source Selector has expressed an interest in not having its
        /// MouseDoubleClick handled the internal reference
        /// </summary>
        private static void OnHandleDoubleClickCommandChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement ele = d as FrameworkElement;
            if (ele != null)
            {
                ele.MouseLeftButtonDown -= OnMouseDoubleClick;
                if (e.NewValue != null)
                {
                    ele.MouseLeftButtonDown += OnMouseDoubleClick;
                }
            }
        }

        /// <summary>
        /// TheCommandToRun : The actual ICommand to run
        /// </summary>
        public static readonly DependencyProperty DoubleClickCommandProperty =
            DependencyProperty.RegisterAttached("DoubleClickCommand",
                typeof(ICommand),
                typeof(MouseDoubleClickBehavior),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnHandleDoubleClickCommandChanged)));

        /// <summary>
        /// Gets the TheCommandToRun property. �
        /// </summary>
        public static ICommand GetDoubleClickCommand(DependencyObject d)
        {
            return (ICommand)d.GetValue(DoubleClickCommandProperty);
        }

        /// <summary>
        /// Sets the TheCommandToRun property. �
        /// </summary>
        public static void SetDoubleClickCommand(DependencyObject d, ICommand value)
        {
            d.SetValue(DoubleClickCommandProperty, value);
        }

        #region Handle the event

        /// <summary>
        /// Invoke the command we tagged.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            //check for double clicks.
            if (e.ClickCount != 2)
                return;
            FrameworkElement ele = sender as FrameworkElement;

            DependencyObject originalSender = e.OriginalSource as DependencyObject;
            if (ele == null || originalSender == null)
                return;

            ICommand command = (ICommand)(sender as DependencyObject).GetValue(DoubleClickCommandProperty);

            if (command != null)
            {
                if (command.CanExecute(null))
                    command.Execute(null);
            }
        }
        #endregion
    }

}

Hopefully this helps you.

Oh, how to use. Almost forgot:

Snippet

xmlns:infraBehaviors="clr-namespace:Seekford.Behaviors;assembly=Seekford"

Snippet

 <Grid infraBehaviors:MouseDoubleClickBehavior.DoubleClickCommand="{Binding MyCommand}"  HorizontalAlignment="Stretch" >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>       �
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition></RowDefinition>
                </Grid.RowDefinitions>
                <TextBlock Text="{Binding Name}" TextWrapping="Wrap" FontWeight="Bold"  Grid.Column="0"  />
            </Grid>

Of course, make your own namespace and correct accordingly. But you already knew that.

Happy Coding!

Bind Title for the ChildWindow to a localized resource using MVVM and Extension

I need to ensure my Silverlight application is localizable, so I am binding to a localizable resource file in the project. The issue is, how do I bind to the Title property? It crashed when trying to bind to a local resource since it hasn’t loaded the resources at this point. Even though the designer shows it working, the application doesn’t like it.

So I originally over engineered this by doing a custom extension. After too much coding, and getting it to work by the way, it dawned on me….Much easier way. Just set the childwindow title property after the resources tag…Argghhhh…….

Easy title binding

<controls:ChildWindow.Resources>
 <res:LocalizedStrings xmlns:local ="clr-namespace:PwC.AuraOnline.Modules.DeployEngagement" x:Key="LocalizedStrings" />
 <infrastructure:BooleanToVisibilityConverter x:Key="boolVisibilityConverter"/>
 </controls:ChildWindow.Resources>
 <controls:ChildWindow.Title>
 <TextBlock Text="{Binding  ClientSearchResources.WindowTitle,Source={StaticResource LocalizedStrings}}"></TextBlock>
 </controls:ChildWindow.Title>

I hope this helps someone out.

Happy Coding!