#1,196 – Making a Window Fully Transparent

You can make the background of a window fully transparent by setting its Background property to Transparent, settings AllowsTransparency to true and setting WindowStyle to None.

Below is an example.  Note that because WindowStyle is None, the window doesn’t have a normal border and we can’t therefore move the window around.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Transparent"
        Height="190" Width="268"
        Background="Transparent"
        AllowsTransparency="True"
        WindowStyle="None"
        WindowStartupLocation="CenterScreen">

    <StackPanel>
        <TextBlock Text="Topper (1937) starred Cary Grant and Constance Bennett"
                   TextWrapping="Wrap"
               HorizontalAlignment="Center" Height="40" Margin="47,0"/>
        <Button Content="Ok, Got It"
                Padding="10,5" Margin="10"
                HorizontalAlignment="Center"
                Click="Button_Click"/>
    </StackPanel>
</Window>

Here’s the window in action. (We added a handler to the button’s Click event to close the window when clicked).

1196-001

#1,195 – Making a Window Partially Transparent

You can use an alpha value when setting a background color to make the background of a control partially transparent.  (E.g. Making a tooltip partially transparent).

You can make the background of a Window transparent, or partially transparent, by doing three things:

  • Set the Background to Transparent or use a background that is partially transparent
  • Set the AllowsTransparency property to true
  • Set the WindowStyle to None

The WindowStyle must be set to None when setting AllowsTransparency to true.

Here’s an example:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Transparent"
        Height="190" Width="268"
        Background="#D5F0F0FF"
        AllowsTransparency="True"
        WindowStyle="None">

    <StackPanel>
        <Button Content="Click Me"
                Padding="10,5" Margin="10"
                HorizontalAlignment="Center"/>
    </StackPanel>
</Window>

We now get a window that doesn’t include a border (so we can’t move it), but whose background is partially transparent.  The controls within a transparent window are opaque and all work fine.

1195-001

#1,105 – Using Application’s Windows Collection to Interact with Other Windows

You can use the Application object’s Windows property to get a list of all active windows.  If you then cast to your specific subclass of Window, you can interact with the various child windows.

Suppose that we have a main window with a button for creating other windows.

        private void btnCreate_Click(object sender, RoutedEventArgs e)
        {
            OtherWindow ow = new OtherWindow();
            ow.Show();
        }

Assume that the child windows have a TextBox that binds to a property in the code-behind.

        <TextBox Text="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                 Margin="10" Height="25"/>

The code-behind would look like this:

    public partial class OtherWindow : Window, INotifyPropertyChanged
    {
        public OtherWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private string someText;
        public string SomeText
        {
            get { return someText; }
            set
            {
                someText = value;
                RaisePropChanged("SomeText");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropChanged(string prop)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }

We can now get information on all child windows as shown below (this is an event handler for another button on the main window).

        private void btnList_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();

            foreach (Window w in Application.Current.Windows)
            {
                OtherWindow ow = w as OtherWindow;
                if (ow != null)
                    sb.AppendLine(ow.SomeText);
            }

            MessageBox.Show(sb.ToString());
        }

1105-001

#1,032 – Show Progress on Windows Taskbar Icon

When your application is doing some work in the background, it’s common to show progress in a ProgressBar within your application.

1032-001

In Windows 7 and Windows 8, you can also make use of the underlying Windows API to show an integrated progress bar on the application’s taskbar icon.  The progress is rendered using a green bar that moves across the width of the icon.  This is helpful for showing progress while your application is minimized.

1032-002

Below is a complete example of how you can update the taskbar icon to show progress.  Some of the low-level API code was taken from the Windows API Code Pack on MSDN, which contains examples of many more API functions that you can call.  You can use the Windows API Code Pack as an external library, or you can call the low-level Windows API yourself.  The code below does the latter and is the minimum code required to show progress on the taskbar.

To start with, we define the following code in a TaskbarAPI.cs file.  This provides a managed wrapper around the underlying Windows API calls.  The main thing is the ITaskbarList4 interface, in its entirety.  We then define some extra stuff for the types that appear in the interface.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace WpfApplication1
{
    internal enum HResult
    {
        Ok = 0x0000

        // Add more constants here, if necessary
    }

    public enum TaskbarProgressBarStatus
    {
        NoProgress = 0,
        Indeterminate = 0x1,
        Normal = 0x2,
        Error = 0x4,
        Paused = 0x8
    }

    internal enum ThumbButtonMask
    {
        Bitmap = 0x1,
        Icon = 0x2,
        Tooltip = 0x4,
        THB_FLAGS = 0x8
    }

    [Flags]
    internal enum ThumbButtonOptions
    {
        Enabled = 0x00000000,
        Disabled = 0x00000001,
        DismissOnClick = 0x00000002,
        NoBackground = 0x00000004,
        Hidden = 0x00000008,
        NonInteractive = 0x00000010
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    internal struct ThumbButton
    {
        ///
/// WPARAM value for a THUMBBUTTON being clicked.
        ///
        internal const int Clicked = 0x1800;

        [MarshalAs(UnmanagedType.U4)]
        internal ThumbButtonMask Mask;
        internal uint Id;
        internal uint Bitmap;
        internal IntPtr Icon;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
        internal string Tip;
        [MarshalAs(UnmanagedType.U4)]
        internal ThumbButtonOptions Flags;
    }

    internal enum SetTabPropertiesOption
    {
        None = 0x0,
        UseAppThumbnailAlways = 0x1,
        UseAppThumbnailWhenActive = 0x2,
        UseAppPeekAlways = 0x4,
        UseAppPeekWhenActive = 0x8
    }

    // using System.Runtime.InteropServices
    [ComImportAttribute()]
    [GuidAttribute("c43dc798-95d1-4bea-9030-bb99e2983a1a")]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    internal interface ITaskbarList4
    {
        // ITaskbarList
        [PreserveSig]
        void HrInit();
        [PreserveSig]
        void AddTab(IntPtr hwnd);
        [PreserveSig]
        void DeleteTab(IntPtr hwnd);
        [PreserveSig]
        void ActivateTab(IntPtr hwnd);
        [PreserveSig]
        void SetActiveAlt(IntPtr hwnd);

        // ITaskbarList2
        [PreserveSig]
        void MarkFullscreenWindow(
            IntPtr hwnd,
            [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);

        // ITaskbarList3
        [PreserveSig]
        void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
        [PreserveSig]
        void SetProgressState(IntPtr hwnd, TaskbarProgressBarStatus tbpFlags);
        [PreserveSig]
        void RegisterTab(IntPtr hwndTab, IntPtr hwndMDI);
        [PreserveSig]
        void UnregisterTab(IntPtr hwndTab);
        [PreserveSig]
        void SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore);
        [PreserveSig]
        void SetTabActive(IntPtr hwndTab, IntPtr hwndInsertBefore, uint dwReserved);
        [PreserveSig]
        HResult ThumbBarAddButtons(
            IntPtr hwnd,
            uint cButtons,
            [MarshalAs(UnmanagedType.LPArray)] ThumbButton[] pButtons);
        [PreserveSig]
        HResult ThumbBarUpdateButtons(
            IntPtr hwnd,
            uint cButtons,
            [MarshalAs(UnmanagedType.LPArray)] ThumbButton[] pButtons);
        [PreserveSig]
        void ThumbBarSetImageList(IntPtr hwnd, IntPtr himl);
        [PreserveSig]
        void SetOverlayIcon(
          IntPtr hwnd,
          IntPtr hIcon,
          [MarshalAs(UnmanagedType.LPWStr)] string pszDescription);
        [PreserveSig]
        void SetThumbnailTooltip(
            IntPtr hwnd,
            [MarshalAs(UnmanagedType.LPWStr)] string pszTip);
        [PreserveSig]
        void SetThumbnailClip(
            IntPtr hwnd,
            IntPtr prcClip);

        // ITaskbarList4
        void SetTabProperties(IntPtr hwndTab, SetTabPropertiesOption stpFlags);
    }

    [GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")]
    [ClassInterfaceAttribute(ClassInterfaceType.None)]
    [ComImportAttribute()]
    internal class CTaskbarList { }
}

Next, we define a little helper class that calls the API on our behalf.  We use a Dispatcher so that we can get access to the application’s main window, doing this on the UI thread.

using System;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;

namespace WpfApplication1
{
    public static class TaskbarUtility
    {
        private static ITaskbarList4 _taskbarList;

        static TaskbarUtility()
        {
            if (!IsSupported())
                throw new Exception("Taskbar functions not available");

            _taskbarList = (ITaskbarList4)new CTaskbarList();
            _taskbarList.HrInit();
        }

        private static bool IsSupported()
        {
            return Environment.OSVersion.Platform == PlatformID.Win32NT &&
                Environment.OSVersion.Version.CompareTo(new Version(6, 1)) >= 0;
        }

        public static void SetProgressState(TaskbarProgressBarStatus state)
        {
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
            {
                _taskbarList.SetProgressState((new WindowInteropHelper(Application.Current.MainWindow)).Handle, state);
            }));
        }

        public static void SetProgressValue(int currentValue, int maximumValue)
        {
            // using System.Windows.Interop
            Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
            {
                _taskbarList.SetProgressValue(
                    (new WindowInteropHelper(Application.Current.MainWindow)).Handle,
                    Convert.ToUInt64(currentValue),
                    Convert.ToUInt64(maximumValue));
            }));
        }
    }
}

The XAML for the example just contains a ProgressBar and a Button to start the background operation.

<Window x:Class="WpfApplication1.MainWindow"
        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"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="ProgressBar"
        Width="280" Height="140">

    <StackPanel>
        <ProgressBar Value="{Binding TheProgress}"
                     Height="15" Margin="15,15,15,0"/>
        <Label Content="Doing some work..."
               Margin="10,0"/>
        <Button Margin="15" Padding="15,3" HorizontalAlignment="Center"
            Content="Start" Click="Button_Click"/>
    </StackPanel>
</Window>

Our code-behind is also fairly simple.  When the user clicks the Button, we start an operation on the background thread and periodically update both the ProgressBar control and the progress bar built into the taskbar icon.

using System.ComponentModel;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private int theProgress = 0;
        public int TheProgress
        {
            get { return theProgress; }
            protected set
            {
                theProgress = value;
                RaisePropertyChanged("TheProgress");
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            new Thread(() =>
            {
                TaskbarUtility.SetProgressState(TaskbarProgressBarStatus.Normal);

                for (int i = 1; i <= 100; i++)
                {
                    TheProgress = i;
                    TaskbarUtility.SetProgressValue(i, 100);
                    Thread.Sleep(50);
                }

                TheProgress = 0;
                TaskbarUtility.SetProgressState(TaskbarProgressBarStatus.NoProgress);
            }).Start();
        }

        // INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        private void RaisePropertyChanged(string propName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }
}

#660 – Changing the Double-Click Speed in Windows 8

When you double-click on a user interface element, Windows gives you a certain amount of time between the two clicks that make up the double-click.  If you wait too long before clicking the mouse a second time, your clicks are treated as two single clicks, rather than one double-click.

You can change the amount of time you’re given between the clicks as follows.

Click on the Windows key to bring up the Start Screen.  Type in mouse and then click on Settings.

Click on Change mouse click settings.

The Mouse Properties window will come up.  On the Buttons tab, you can change the time allowed for double-clicks using the slider in the Double-click speed section.

Changing the setting to become more Slow means that you can wait longer before the second half of the double-click.  (Up to 900 milliseconds).  Fast means that you have less time (as little as 200 milliseconds).

#614 – Events that Fire When You Switch Between Windows

If your application has multiple windows, the user can switch between the different windows.  The sequence of events when switching from one window (1) to another (2) is as follows:

  • Window.Deactivated  (#1)
  • Window.Activated  (#2)
  • Window.PreviewLostKeyboardFocus  (#1)
  • Window.PreviewGotKeyboardFocus  (#2)
  • Window.IsKeyboardFocusWithinChanged  (#1)
  • Window.IsKeyboardFocusWithinChanged  (#2)
  • Window.IsKeyboardFocusChanged  (#1)
  • Window.IsKeyboardFocusChanged  (#2)
  • Window.LostKeyboardFocus  (#1)
  • Window.GotKeyboardFocus  (#2)
  • Window.Deactivated  (#2)

#613 – Window Event Sequence

The full sequence of events fired for a Window object are as follows.

On application startup, if the Window is the application’s main window.  (Application events are also shown in the correct sequence).

  • Application.Startup
  • Window.Initialized
  • Window.IsVisibleChanged
  • Window.SizeChanged
  • Window.LayoutUpdated
  • Window.SourceInitialized
  • Application.Activated
  • Window.Activated
  • Window.PreviewGotKeyboardFocus
  • Window.IsKeyboardFocusWithinChanged
  • Window.IsKeyboardFocusedChanged
  • Window.GotKeyboardFocus
  • Window.LayoutUpdated
  • Window.Loaded
  • Window.ContentRendered

On normal application shutdown, the event sequence is:

  • Window.Closing
  • Window.IsVisibleChanged
  • Window.Deactivated
  • Application.Deactivated
  • Window.IsKeyboardFocusWithinChanged
  • Window.IsKeyboardFocusedChanged
  • Window.LostKeyboardFocus
  • Window.Closed
  • Application.Exit

When application/window loses focus (user switches to another application):

  • Window.Deactivated
  • Application.Deactivated
  • Window.IsKeyboardFocusWithinChanged
  • Window.IsKeyboardFocusedChanged
  • Window.LostKeyboardFocus

When application/window gains focus (user switches back to application):

  • Application.Activated
  • Window.Activated
  • Window.PreviewGotKeyboardFocus
  • Window.IsKeyboardFocusWithinChanged
  • Window.IsKeyboardFocusChanged
  • Window.GotKeyboardFocus