#831 – Embedding a Cursor in Your Project as a Resource

If you have a custom cursor that your application uses, you can load it at run-time from an external file.  But this requires that you distribute the cursor file with your application.  To avoid distributing the .cur file, you can embed this file into your project as a resource.

First, add the .cur file to your project and set its Build Action to Resource.

831-001

831-002

831-003

831-004

To load the cursor at run-time, you use the Application.GetResourceStream method, which returns a StreamResourceInfo object.  You can then use the Stream property of this object to create the cursor.  (You’ll need a using statement for the System.Windows.Resources namespace).

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            StreamResourceInfo sriCurs = Application.GetResourceStream(
                new Uri("captain-america-arrow.cur", UriKind.Relative));

            this.Cursor = new Cursor(sriCurs.Stream);
        }

831-005

#830 – Loading a Cursor from a File

You can set a cursor in your application to a cursor that you load from a .cur or .ani file.  The constructor for the System.Windows.Input.Cursor class accepts either a filename or a stream.  If you use a filename, you should use the full path to your cursor file.

In the example below, we set the cursor for the parent window to one of two different cursors, depending on which button we click.

    <StackPanel>
        <Button Content="Steve Rogers" Margin="10"
               Click="Button_Click_1"/>
        <Button Content="Peggy Carter" Margin="10"
                Click="Button_Click_2"/>
    </StackPanel>

 

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            string fullPath = Path.Combine(Environment.CurrentDirectory, "captain-america-arrow.cur");
            this.Cursor = new Cursor(fullPath);
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            string fullPath = Path.Combine(Environment.CurrentDirectory, "captain-america-shield.ani");
            this.Cursor = new Cursor(fullPath);
        }

830-001
830-002

#829 – Setting an Application-Wide Cursor from Code

You can use the Cursors property of a FrameworkElement to set the cursor that the user sees when moving the mouse over that element.  This cursor will also be used on descendant elements of the element where you set the cursor.

You can also set the cursor from code.  You could just set the Cursor property of an individual element in code.  But you can also set the static Mouse.OverrideCursor property, indicating a cursor that should be used throughout the entire application.  This will override any Cursor properties of individual elements.

    <StackPanel>
        <Label Content="Ad eundum quo nemo ante iit"
               Background="LightCoral"
               Cursor="Hand"/>
        <Label Content="Noli habere bovis, vir"
               Background="DarkSeaGreen"/>
        <Button Content="Ventilabis Me"
                Click="btnClick"
                HorizontalAlignment="Center"/>
    </StackPanel>

 

        private void btnClick(object sender, RoutedEventArgs e)
        {
            Mouse.OverrideCursor = Cursors.AppStarting;
        }

829-001
829-002

#827 – Overriding the Cursor Properties of Child Elements

A child FrameworkElement can set a Cursor value that overrides the current Cursor value set by a parent (or ancestor) element.  This new Cursor value then applies in the element where it is set and any of its own child elements.

A parent/ancestor FrameworkElement can, however, force all child elements to use a particular cursor, by setting the ForceCursor property to true.  This overrides any Cursor property values that the child elements might set.

In the example below, the second Button sets its Cursor property to Hand, but this value is overridden because the parent StackPanel sets the ForceCursor property to true.

    <StackPanel Cursor="Hand" ForceCursor="True">
        <Label Content="Ad eundum quo nemo ante iit"
               Margin="5"
               Background="LightCoral"/>
        <Label Content="Noli habere bovis, vir"
               Margin="5"
               Background="DarkSeaGreen"/>
        <StackPanel Orientation="Horizontal"
                    HorizontalAlignment="Center">
            <Button Content="Veni, Vidi"
                    Padding="10,5" Margin="10"/>
            <Button Content="Dormivi"
                    Cursor="Wait"
                    Padding="10,5" Margin="10"/>
        </StackPanel>
    </StackPanel>

827-001
827-002

#826 – Lower-Level Elements Can Have Different Cursor

Cursor set on a top-level FrameworkElement will also be used on all elements within the parent element’s logical tree.  All lower-level elements will show the same cursor when the user hovers over the element.

You can, however, set a Cursor on a top-level element and then set a different value for Cursor on the lower-level element.  The top-level Cursor will be used for all descendants of the top-level element except for the one that explicitly sets a different cursor.

    <StackPanel Cursor="Hand">
        <Label Content="Ad eundum quo nemo ante iit"
               Margin="5"
               Background="LightCoral"/>
        <Label Content="Noli habere bovis, vir"
               Margin="5"
               Background="DarkSeaGreen"/>
        <StackPanel Orientation="Horizontal"
                    HorizontalAlignment="Center">
            <Button Content="Veni, Vidi"
                    Padding="10,5" Margin="10"/>
            <Button Content="Dormivi"
                    Cursor="Wait"
                    Padding="10,5" Margin="10"/>
        </StackPanel>
    </StackPanel>

826-001
826-002

#824 – Setting a Cursor on a Top Level Element

When you set the Cursor property on a FrameworkElement, the cursor is displayed whenever you move the mouse pointer over that element.  This Cursor value will also apply to all descendants of the element.

In the example below, when we set the Cursor in the top-level Window, that cursor is used for all elements contained in the window.

Layout, within the Window:

    <StackPanel>
        <Label Content="Ad eundum quo nemo ante iit"
               Margin="5"
               Background="LightCoral"/>
        <Label Content="Noli habere bovis, vir"
               Margin="5"
               Background="DarkSeaGreen"/>
        <StackPanel Orientation="Horizontal"
                    HorizontalAlignment="Center">
            <Button Content="Veni, Vidi"
                    Padding="10,5" Margin="10"
                    Click="btnClick_Wait"/>
            <Button Content="Dormivi"
                    Padding="10,5" Margin="10"
                    Click="btnClick_StopWaiting"/>
        </StackPanel>
    </StackPanel>

Code-behind:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void btnClick_Wait(object sender, RoutedEventArgs e)
        {
            this.Cursor = Cursors.AppStarting;
        }

        private void btnClick_StopWaiting(object sender, RoutedEventArgs e)
        {
            this.Cursor = Cursors.Arrow;
        }
    }

824-001
824-002
824-003
824-004
824-005

#823 – Setting a Cursor from XAML

Every FrameworkElement has a Cursor property that you can set to an instance of a System.Windows.Input.Cursor object.  Typically, you’ll just set the property to one of the predefined cursors in the System.Windows.Input.Cursors class.

When you set the Cursor property on an element, you’re indicating which cursor should appear when a user moves the mouse over that element.

You can set the Cursor property in XAML or in code.  In either case, you can pick from one of the predefined cursors in System.Windows.Input.Cursors.  In the image below, Intellisense in Visual Studio shows a list of the available cursors when setting the Cursor property from XAML.

823-001

In the example below, we indicate that we want the Wait cursor displayed whenever we hover over the second label.

    <StackPanel>
        <Label Content="I'm just a label, you know?"
               Margin="5"
               Background="LightCoral"/>
        <Label Content="I'm waiting and waiting"
               Margin="5"
               Background="DarkSeaGreen"
               Cursor="Wait"/>
    </StackPanel>

823-002
823-003

#714 – Setting the Cursor to Render Some Text While Dragging

You can use the GiveFeedback to change the cursor during a drag-and-drop operation.  You can set the cursor to be some text by rendering a visual element to a bitmap and then converting that bitmap to a cursor.

Here’s a helper class containing a method that converts some text to a cursor.

    public class CursorHelper
    {
        private static class NativeMethods
        {
            public struct IconInfo
            {
                public bool fIcon;
                public int xHotspot;
                public int yHotspot;
                public IntPtr hbmMask;
                public IntPtr hbmColor;
            }

            [DllImport("user32.dll")]
            public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon);

            [DllImport("user32.dll")]
            public static extern bool DestroyIcon(IntPtr hIcon);

            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
        }

        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        private class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            public SafeIconHandle()
                : base(true)
            {
            }

            override protected bool ReleaseHandle()
            {
                return NativeMethods.DestroyIcon(handle);
            }
        }

        private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp)
        {
            var iconInfo = new NativeMethods.IconInfo();
            NativeMethods.GetIconInfo(bmp.GetHicon(), ref iconInfo);

            iconInfo.xHotspot = 0;
            iconInfo.yHotspot = 0;
            iconInfo.fIcon = false;

            SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo);
            return CursorInteropHelper.Create(cursorHandle);
        }

        public static Cursor CreateCursor(string cursorText)
        {
            // Text to render
            FormattedText fmtText = new FormattedText(cursorText,
                    new CultureInfo("en-us"),
                    FlowDirection.LeftToRight,
                    new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Normal, new FontStretch()),
                    12.0,  // FontSize
                    Brushes.Black);

            // The Visual to use as the source of the RenderTargetBitmap.
            DrawingVisual drawingVisual = new DrawingVisual();
            DrawingContext drawingContext = drawingVisual.RenderOpen();
            drawingContext.DrawText(fmtText, new Point());
            drawingContext.Close();

            // The BitmapSource that is rendered with a Visual.
            RenderTargetBitmap rtb = new RenderTargetBitmap(
                (int)drawingVisual.ContentBounds.Width,
                (int)drawingVisual.ContentBounds.Height,
                96,   // dpiX
                96,   // dpiY
                PixelFormats.Pbgra32);
            rtb.Render(drawingVisual);

            // Encoding the RenderBitmapTarget into a bitmap (as PNG)
            PngBitmapEncoder encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));

            using (var ms = new MemoryStream())
            {
                encoder.Save(ms);
                using (var bmp = new System.Drawing.Bitmap(ms))
                {
                    return InternalCreateCursor(bmp);
                }
            }
        }
    }

We can test this code by setting the cursor to some text when we drag a Label.

    <StackPanel>
        <Label Content="Mayflower" Background="AliceBlue" 
               HorizontalAlignment="Center" Margin="15" Padding="20,5"
               MouseLeftButtonDown="Label_MouseLeftButtonDown"
               GiveFeedback="Label_GiveFeedback"/>
        <Label Content="Drag to here" Background="SpringGreen" 
               HorizontalAlignment="Center" Margin="15"
               Drop="Label_Drop"/>
    </StackPanel>

Here’s the code for the drag-and-drop operation.

        private void Label_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataObject data = new DataObject(DataFormats.Text, ((Label)e.Source).Content);

            DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Copy);
        }

        private void Label_Drop(object sender, DragEventArgs e)
        {
            ((Label)e.Source).Content = (string)e.Data.GetData(DataFormats.Text);
        }

        private Cursor customCursor = null;

        private void Label_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            if (e.Effects == DragDropEffects.Copy)
            {
                if (customCursor == null)
                    customCursor = CursorHelper.CreateCursor("Mayflower - 18 Dec 1620");

                if (customCursor != null)
                {
                    e.UseDefaultCursors = false;
                    Mouse.SetCursor(customCursor);
                }
            }
            else
                e.UseDefaultCursors = true;

            e.Handled = true;
        }

714-001

#713 – Setting the Cursor to an Image of an UIElement While Dragging

You can use the GiveFeedback to change the cursor during a drag-and-drop operation.  You can go a bit further and set the cursor to an image that represents the user interface element that you are dragging by rendering the UIElement to a bitmap and then converting that bitmap to a cursor.

This example is based on code written by Brandon Cannaday, at http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-custom-cursors .  To start with, here is Brandon’s code, as modified by reader “Swythan”:

    public class CursorHelper
    {
        private static class NativeMethods
        {
            public struct IconInfo
            {
                public bool fIcon;
                public int xHotspot;
                public int yHotspot;
                public IntPtr hbmMask;
                public IntPtr hbmColor;
            }

            [DllImport("user32.dll")]
            public static extern SafeIconHandle CreateIconIndirect(ref IconInfo icon);

            [DllImport("user32.dll")]
            public static extern bool DestroyIcon(IntPtr hIcon);

            [DllImport("user32.dll")]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
        }

        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        private class SafeIconHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            public SafeIconHandle()
                : base(true)
            {
            }

            override protected bool ReleaseHandle()
            {
                return NativeMethods.DestroyIcon(handle);
            }
        }

        private static Cursor InternalCreateCursor(System.Drawing.Bitmap bmp)
        {
            var iconInfo = new NativeMethods.IconInfo();
            NativeMethods.GetIconInfo(bmp.GetHicon(), ref iconInfo);

            iconInfo.xHotspot = 0;
            iconInfo.yHotspot = 0;
            iconInfo.fIcon = false;

            SafeIconHandle cursorHandle = NativeMethods.CreateIconIndirect(ref iconInfo);
            return CursorInteropHelper.Create(cursorHandle);
        }

        public static Cursor CreateCursor(UIElement element)
        {
            element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            element.Arrange(new Rect(new Point(), element.DesiredSize));

            RenderTargetBitmap rtb =
              new RenderTargetBitmap(
                (int)element.DesiredSize.Width,
                (int)element.DesiredSize.Height,
                96, 96, PixelFormats.Pbgra32);

            rtb.Render(element);

            var encoder = new PngBitmapEncoder();
            encoder.Frames.Add(BitmapFrame.Create(rtb));

            using (var ms = new MemoryStream())
            {
                encoder.Save(ms);
                using (var bmp = new System.Drawing.Bitmap(ms))
                {
                    return InternalCreateCursor(bmp);
                }
            }
        }
    }

Now that we have the helper class, we can use it to set the cursor to the image of a Label that we are dragging. Here’s the XAML defining a label to drag from and one to drag to.

    <StackPanel Orientation="Vertical" HorizontalAlignment="Center" Margin="45">
        <Label Content="Data to drag" Background="AliceBlue" Padding="15,10"
               MouseLeftButtonDown="Label_MouseLeftButtonDown"
               GiveFeedback="Label_GiveFeedback"/>
        <Label Content="Drag to here" Background="MediumSpringGreen" Padding="15,10" Margin="20"
               AllowDrop="True" Drop="Label_Drop"/>
    </StackPanel>

Here’s the relevant drag-and-drop related code:

        private void Label_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataObject data = new DataObject(DataFormats.Text, ((Label)e.Source).Content);

            DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Copy);
        }

        private void Label_Drop(object sender, DragEventArgs e)
        {
            ((Label)e.Source).Content = (string)e.Data.GetData(DataFormats.Text);
        }

        private Cursor customCursor = null;

        private void Label_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            if (e.Effects == DragDropEffects.Copy)
            {
                if (customCursor == null)
                    customCursor = CursorHelper.CreateCursor(e.Source as UIElement);

                if (customCursor != null)
                {
                    e.UseDefaultCursors = false;
                    Mouse.SetCursor(customCursor);
                }
            }
            else
                e.UseDefaultCursors = true;

            e.Handled = true;
        }

#712 – Showing a Custom Mouse Cursor While Dragging

You can use a non-default cursor while a drag-and-drop operation is in process by handling the GiveFeedback event.

In the example below, we load a custom cursor from a .cur file located in the same directory as the executing application.

        private void Label_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DataObject data = new DataObject(DataFormats.Text, ((Label)e.Source).Content);

            DragDrop.DoDragDrop((DependencyObject)e.Source, data, DragDropEffects.Copy);
        }

        private void Label_Drop(object sender, DragEventArgs e)
        {
            ((Label)e.Source).Content = (string)e.Data.GetData(DataFormats.Text);
        }

        private Cursor customCursor = null;

        private void Label_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        {
            if (e.Effects == DragDropEffects.Copy)
            {
                if (customCursor == null)
                    customCursor = new Cursor(new FileStream("Earth.cur", FileMode.Open));

                e.UseDefaultCursors = false;
                Mouse.SetCursor(customCursor);
            }
            else
                e.UseDefaultCursors = true;

            e.Handled = true;
        }

712-001