All posts tagged software

That’s what’s up. We are going to stop windows from stealing focus with C#. No frills, no crap, no more of this nonsense. It’s time to stop.

Q: Why does Windows do this and why isn’t there a setting to fix this?
A: Remember Fred Johnson who lived down the street in the 70’s? You know… that slightly overweight jerk that bullied the smart kids? Well, one day on the way home from school he kicked Billy Gates dog and said something off color about his “parentage”. So, now we need to suffer for Fred’s sins. No need to Wiki this, it’s a true story.

 
Joking Aside

So, back in the early 2000’s we had the Windows XP PowerToy called TweakUI which allowed us to control how initialized windows interacted with the desktop environment. This involved changing the following registry key:

HKEY_CURRENT_USER\Control Panel\Desktop\Foreground\LockTimeout

In the modern versions of Windows, this override no longer works. For a long while, this left us SOL and drifting in space looking for the answer… that is until now.

 
The Solution

In my opinion, the C# community was right in thinking the best approach is to get on the P/Invoke track.

For this solution the key is LockSetForegroundWindow on a timer. For this solution we will use the following methods:


// Lock
public static uint LSFW_LOCK = 1;
public static uint LSFW_UNLOCK = 2;

/// <summary>
/// Locks the set foreground window.
/// </summary>
/// <param name="uLockCode">The u lock code.</param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool LockSetForegroundWindow(uint uLockCode);

/// <summary>
/// Gets the foreground window.
/// </summary>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();

 
Now that we have identified the P/Invoke piece, let’s look at how we can implement this effectively with said timer in a WPF application. To do this we are going to create a controller to facilitate all our focus needs:


using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Threading;

using Win32Windows = Xcalibur.Win32.Win32ApiHelper.Windows;

namespace Xcalibur.DontInterruptMe
{
    /// <summary>
    /// Window focus controller.
    /// </summary>
    public class FocusController
    {
        #region Members
        
        private readonly DispatcherTimer _timer;
        private IntPtr _currentHandle;
        private bool _isRunning;
        private bool _isStarted;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="FocusController"/> class.
        /// </summary>
        public FocusController()
        {
            this._isRunning = false;
            this._isStarted = false;

            // Set timer
            this._timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) };
            this._timer.Tick += (s, e) => this.EvaluateAsync(); 

            // Start
            this.Start();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Starts this instance.
        /// </summary>
        public void Start()
        {
            if (this._isStarted) return;

            // Start timer
            this._timer.IsEnabled = true;
            this._timer.Start();
            this._isStarted = true;
        }

        /// <summary>
        /// Stops this instance.
        /// </summary>
        public void Stop()
        {
            if (!this._isStarted) return;

            // Stop timer
            this._timer.Stop();
            this._timer.IsEnabled = false;
            this._isStarted = false;

            // Unlock set foreground window
            LockSetForegroundWindow(LSFW_UNLOCK);
        }

        /// <summary>
        /// Evaluates this instance.
        /// </summary>
        private void Evaluate()
        {
            if (_isRunning) return;

            // Set as "running"
            _isRunning = true;

            // Get current
            var activeWindowHandle = GetForegroundWindow();
            if (_currentHandle == activeWindowHandle)
            {
                _isRunning = false;
                return;
            }

            // Store current handle
            _currentHandle = activeWindowHandle;

            // Handle cannot be 0
            if (activeWindowHandle == IntPtr.Zero)
            {
                _isRunning = false;
                return;
            }

            // Get related process
            var processes = Process.GetProcesses();
            var currentProcess = processes.FirstOrDefault(x => x.MainWindowHandle == _currentHandle);

            // currentProcess must exist, and the MainWindowTitle must be valid.
            if (currentProcess == null || string.IsNullOrEmpty(currentProcess.MainWindowTitle))
            {
                _isRunning = false;
                return;
            }

            // Lock set foreground window
            LockSetForegroundWindow(LSFW_LOCK);

            // Set as "not running"
            _isRunning = false;
        }

        /// <summary>
        /// Evaluates the asynchronous.
        /// </summary>
        /// <returns></returns>
        private async Task EvaluateAsync()
        {
            await Task.Run(() => this.Evaluate());
        }

        #endregion

        #region P/Invoke 

        // Lock
        public static uint LSFW_LOCK = 1;
        public static uint LSFW_UNLOCK = 2;

        /// <summary>
        /// Locks the set foreground window.
        /// </summary>
        /// <param name="uLockCode">The u lock code.</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern bool LockSetForegroundWindow(uint uLockCode);

        /// <summary>
        /// Gets the foreground window.
        /// </summary>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();

        #endregion
    }
}

 
The last piece is the implementation of the FocusController from App.xaml:


using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using Hardcodet.Wpf.TaskbarNotification;

using Microsoft.Win32;
using Application = System.Windows.Application;

namespace Xcalibur.DontInterruptMe
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        #region Members

        private static Mutex _instanceMutex;
        private FocusController _focusController;

        #endregion

        #region Methods

        /// <summary>
        /// Checks if application is already running.
        /// </summary>
        /// <returns></returns>
        private static bool StartInstance()
        {
            // Set mutex
            _instanceMutex = new Mutex(true, Constants.ApplicationKey);

            // Check if already running
            bool isAlreadyInUse = false;
            try
            {
                isAlreadyInUse = !_instanceMutex.WaitOne(TimeSpan.Zero, true);
            }
            catch (AbandonedMutexException)
            {
                KillInstance();
                isAlreadyInUse = false;
            }
            catch (Exception)
            {
                _instanceMutex.Close();
                isAlreadyInUse = false;
            }
            return isAlreadyInUse;
        }

        /// <summary>
        /// Kills the instance.
        /// </summary>
        /// <param name="code">The code.</param>
        private static void KillInstance(int code = 0)
        {
            if (_instanceMutex == null) return;

            // Owning application should release mutex
            if (code == 0)
            {
                try
                {
                    _instanceMutex.ReleaseMutex();
                }
                catch (Exception) { }
            }
            _instanceMutex.Close();
        }

        #endregion

        #region Events

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Application.Startup" /> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the 
        /// event data.</param>
        protected override void OnStartup(StartupEventArgs e)
        {
            // Check if running
            if (StartInstance())
            {
                // Already running, Exit
                Current.Shutdown(1);
            }

            // Invoke focus controller
            this._focusController = new FocusController();

            // Base
            base.OnStartup(e);
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Application.Exit" /> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.Windows.ExitEventArgs" /> that contains the 
        /// event data.</param>
        protected override void OnExit(ExitEventArgs e)
        {
            if (this._focusController != null)
            {
                // Gracefully exit
                this._focusController.Stop();
            }

            // Kill instance
            KillInstance(e.ApplicationExitCode);

            // Base
            base.OnExit(e);
        }

        #endregion
    }
}

 
You will notice I added the RunOnce Mutex Solution from our last post Restricting WPF Applications to run only once with a Mutex to avoid any potential issues with multiple instances.

 
Future Changes

In the next version of this application I will be tossing Process.GetProcesses() from the Evaluate method for a much faster P/Invoke solution I am planning to use in the next version of Astronomy.

If you want the complete, free product, download Don’t Interrupt Me! now.

Otherwise my friends, Happy Coding!

As you may know, there is no double-click event for an Image in WPF. However, there are definitely cases where we might want one. But the question is, how do we pull this off while upholding a pure MVVM implementation?

Some considerations:

  • Consideration 1: We should use Commands instead of Events.
  • Consideration 2: In order to get 2 clicks, we will have to look at the MouseDown event, and look at it’s ClickCount since that is something an Image can handle.
  • Consideration 3: Since this is an Image, there is no inherent Command property. In this case, we will need to use a library that provides one.

To start, let’s create a separate class that implements ICommand. In this example all we are doing is firing a MessageBox on successful completion of the event. In a pure implementation a MessageBox would not be considered kosher, but we are just going to use it for our example so we know if it worked:

using System;
using System.Windows;
using System.Windows.Input;

namespace DoubleClickImageTest
{
    /// <summary>
    /// A test command.
    /// </summary>
    public class TestCommand : ICommand
    {
        public virtual bool CanExecute(object parameter)
        {
            return true;
        }

        public virtual void Execute(object parameter)
        {
            // We shouldn't put message boxes in commands normally, but we will for this test.
            MessageBox.Show("Hey, we just double-clicked our Image!",
                "Double-Click Test", MessageBoxButton.OK);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

Next, because this is MVVM we should create a View Model that will hold our command as a property:

using System;

namespace DoubleClickImageTest
{
    public class TestViewModel
    {
        #region Properties

        /// <summary>
        /// Gets or sets my command.
        /// </summary>
        /// <value>
        /// My command.
        /// </value>
        public TestCommand MyCommand { get; set; }

        #endregion

        #region Constructors
        
        /// <summary>
        /// Initializes a new instance of the <see cref="TestViewModel"/> class.
        /// </summary>
        public TestViewModel()
        {
            MyCommand = new TestCommand();
        }

        #endregion
    }
}

To finish setting up the View Model, we will add it to the code-behind of our View and set the Data Context of the View to the View Model instance.

using System;
using System.Windows;

namespace DoubleClickImageTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Members
        
        private TestViewModel _vm;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            // Get and set VM
            _vm = new TestViewModel();
            this.DataContext = _vm;

            // Initialize UI
            InitializeComponent();
        }

        #endregion
    }
}

We have now satisfied the conditions of Consideration 1.

In order to satisfy Consideration 2, we will need to do the following:

  1. Write a class called CustomImage that extends System.Windows.Control.Image.
  2. In CustomImage create a RoutedEvent and RoutedEventHandler to facilitate the double-click event.
  3. In CustomImage override OnMouseLeftButtonDown to evaluate the click count.

First, we create the RoutedEvent:

/// <summary>
/// The mouse left button double click event
/// </summary>
public static readonly RoutedEvent MouseLeftButtonDoubleClick =
    EventManager.RegisterRoutedEvent(
        "MouseLeftButtonDoubleClick",
        RoutingStrategy.Bubble,
        typeof(RoutedEventHandler),
        typeof(CustomImage));

Next we will create the RoutedEventHandler to execute MouseLeftButtonDoubleClick :

/// <summary>
/// Occurs when [mouse left button double click event handler].
/// </summary>
public event RoutedEventHandler MouseLeftButtonDoubleClickEvent
{
    add
    {
        AddHandler(MouseLeftButtonDoubleClick, value);
    }
    remove
    {
        RemoveHandler(MouseLeftButtonDoubleClick, value);
    }
}

Lastly, we need to override the OnMouseLeftButtonDown event.

So, why are we doing this? We know images have OnMouseLeftButtonDown, so we can use that to observe the click-count and call our event. In this case, we observe the ClickCount of our MouseButtonEventArgs. If we observe 2 clicks, we raise the MouseLeftButtonDoubleClick event:

/// <summary>
/// Invoked when an unhandled <see cref="E:System.Windows.UIElement.MouseLeftButtonDown" /> 
/// routed event is raised on this element. Implement this method to add class handling for 
/// this event.
/// </summary>
/// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that 
/// contains the event data. The event data reports that the left mouse button was pressed.
/// </param>
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
    // Double-click
    if (e.ClickCount == 2)
    {
        RaiseEvent(new MouseLeftButtonDoubleClickEventArgs(
            MouseLeftButtonDoubleClick, this));
    }
    base.OnMouseLeftButtonDown(e);
}

/// <summary>
/// MouseLeftButtonDoubleClick EventArgs.
/// </summary>
public class MouseLeftButtonDoubleClickEventArgs : RoutedEventArgs
{
    /// <summary>
    /// Initializes a new instance of the <see cref="MouseLeftButtonDoubleClickEventArgs"/> 
    /// class.
    /// </summary>
    /// <param name="routedEvent">The routed event identifier for this instance of the 
    /// <see cref="T:System.Windows.RoutedEventArgs" /> class.</param>
    /// <param name="source">An alternate source that will be reported when the event is 
    /// handled. This pre-populates the
    /// <see cref="P:System.Windows.RoutedEventArgs.Source" /> property.</param>
    public MouseLeftButtonDoubleClickEventArgs(RoutedEvent routedEvent, object source)
        : base(routedEvent, source)
    {
    }
}

So, in it’s entirety, the CustomImage class looks like this:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace DoubleClickImageTest
{
    /// <summary>
    /// Custom image.
    /// </summary>
    public class CustomImage : Image
    {
        /// <summary>
        /// The mouse left button double click event
        /// </summary>
        public static readonly RoutedEvent MouseLeftButtonDoubleClick =
            EventManager.RegisterRoutedEvent(
                "MouseLeftButtonDoubleClick",
                RoutingStrategy.Bubble,
                typeof(RoutedEventHandler),
                typeof(CustomImage));

        /// <summary>
        /// Occurs when [mouse left button double click event handler].
        /// </summary>
        public event RoutedEventHandler MouseLeftButtonDoubleClickEvent
        {
            add
            {
                AddHandler(MouseLeftButtonDoubleClick, value);
            }
            remove
            {
                RemoveHandler(MouseLeftButtonDoubleClick, value);
            }
        }

        /// <summary>
        /// Invoked when an unhandled <see cref="E:System.Windows.UIElement.MouseLeftButtonDown" /> 
        /// routed event is raised on this element. Implement this method to add class handling for 
        /// this event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that 
        /// contains the event data. The event data reports that the left mouse button was pressed.
        /// </param>
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            // Double-click
            if (e.ClickCount == 2)
            {
                RaiseEvent(new MouseLeftButtonDoubleClickEventArgs(
                    MouseLeftButtonDoubleClick, this));
            }
            base.OnMouseLeftButtonDown(e);
        }

        /// <summary>
        /// MouseLeftButtonDoubleClick EventArgs.
        /// </summary>
        public class MouseLeftButtonDoubleClickEventArgs : RoutedEventArgs
        {
            /// <summary>
            /// Initializes a new instance of the <see cref="MouseLeftButtonDoubleClickEventArgs"/> 
            /// class.
            /// </summary>
            /// <param name="routedEvent">The routed event identifier for this instance of the 
            /// <see cref="T:System.Windows.RoutedEventArgs" /> class.</param>
            /// <param name="source">An alternate source that will be reported when the event is 
            /// handled. This pre-populates the
            /// <see cref="P:System.Windows.RoutedEventArgs.Source" /> property.</param>
            public MouseLeftButtonDoubleClickEventArgs(RoutedEvent routedEvent, object source)
	            : base(routedEvent, source)
            {
            }
        }
    }
}

For Consideration 3 we need to extend our image to allow Commanding, and to do that we will use the Interactivity Library from Expression Blend.

Now, we will build our XAML. Let’s start by adding our CustomImage to a window:

<Window x:Class="DoubleClickImageTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DoubleClickImageTest"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <local:CustomImage 
            Width="200"
            Height="200"
            Source="/DoubleClickImageTest;component/cat_popcorn.jpg" 
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
        </local:CustomImage>
    </Grid>
</Window>

It looks like this at runtime:

Popcorn Cat

So far, there is nothing overly significant about this implementation. Our CustomImage is behaving just like a normal image and it’s center-mass in our window.

Now, let’s add our new MouseLeftButtonDoubleClick event.

<Window x:Class="DoubleClickImageTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DoubleClickImageTest"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:CustomImage 
            Width="200"
            Height="200"
            Source="/DoubleClickImageTest;component/cat_popcorn.jpg" 
            HorizontalAlignment="Center"
            VerticalAlignment="Center">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseLeftButtonDoubleClickEvent">
                    <i:InvokeCommandAction Command="{Binding Path=MyCommand}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </local:CustomImage>
    </Grid>
</Window>

You will notice we included the Interactivity Library in the header:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

Also, this new block inside CustomImage:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="MouseLeftButtonDoubleClickEvent">
        <i:InvokeCommandAction Command="{Binding Path=MyCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

This says: “whenever MouseLeftButtonDoubleClick is fired, invoke MyCommand“.

Note: you will notice this works exactly the same as setting a command on a Button.

So, now when we double-click our image, we see this:

Popcorn Cat with a double-click event

And just like that, we created our double-clickable image.

Until next time…