One of the really great things you can do with WPF is use Mouse.OverrideCursor
to set the cursor for the entire application. This is useful, for instance, if you want your application to perform a lengthy operation, and have the cursor change to a wait cursor, for the duration of the operation. You'd normally do this like:
public void DoAReallyLongOperation()
{
Cursor savedCursor = Mouse.OverrideCursor;
try
{
PerformMyLengthyOperation();
}
finally
{
Mouse.OverrideCursor = savedCursor
}
}
So far, so good. Now, of course, you're going to run off to your Silverlight applications and do exactly the same for your lengthy operations, aren't you? After all, Silverlight is a lightweight version of WPF, so surely this will be there for you to use.
Well no. Silverlight doesn't support the OverrideCursor
, but adding it shouldn't be too hard, should it? Well, it turns out that adding the OverrideCursor
isn't as easy as you'd think it would be. If you change the cursor on your page to a wait cursor, for instance, it will still be an IBeam
when you move over a text box. This means that your code needs to traverse the visual tree looking for all of the child elements, and setting the cursor to the new cursor.
Edit: Since I posted this earlier today, an edge case was suggested that needed addressing. Basically, the code needs to be able to reset the text boxes back to the IBeam
assuming that the OverrideCursor
is set back.
The following class provides an attached property that should help greatly with this:
public class Mouse : DependencyObject
{
#region Members
private static Cursor _oldCursor;
private static bool _isResetting = false;
private static Cursor _overrideCursor;
#endregion
<param name="current">The element to iterate over.</param>
<param name="cursor">The cursor to set to.</param>
internal static void TraverseVisualTree(object current, Cursor cursor)
{
DependencyObject ob = current as DependencyObject;
if (ob != null)
{
if (ob is FrameworkElement)
{
FrameworkElement element = ob as FrameworkElement;
Cursor oldCursor = GetOldCursor(element);
Cursor newCursor = cursor;
if (_isResetting)
{
newCursor = oldCursor;
SetOldCursor(element, null);
}
else
{
SetOldCursor(element, element.Cursor);
}
element.Cursor = newCursor;
}
int counter = VisualTreeHelper.GetChildrenCount(ob);
for (int i = 0; i < counter; i++)
{
object depObj = VisualTreeHelper.GetChild(ob, i);
TraverseVisualTree(depObj, cursor);
}
}
}
public static readonly DependencyProperty OverrideCursorProperty =
DependencyProperty.RegisterAttached("OverrideCursor",
typeof(Cursor),
typeof(UserControl),
new PropertyMetadata(null, OnCursorChanged));
private static readonly DependencyProperty OldCursorProperty =
DependencyProperty.RegisterAttached("OldCursor",
typeof(Cursor),
typeof(UserControl),
new PropertyMetadata(null));
private static void OnCursorChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
if (!(source is FrameworkElement))
return;
_isResetting = (_oldCursor == e.NewValue);
if (!_isResetting)
{
_oldCursor = e.OldValue as Cursor;
}
TraverseVisualTree(source, e.NewValue as Cursor);
}
<param name="source">The object to get the override cursor for.</param>
public static Cursor GetOverrideCursor(DependencyObject source)
{
return source.GetValue(OverrideCursorProperty) as Cursor;
}
<param name="source">The object to set the cursor for.</param>
<param name="value">The cursor value to set.</param>
public static void SetOverrideCursor(DependencyObject source, object value)
{
source.SetValue(OverrideCursorProperty, value);
}
<param name="source">The object to set the cursor for.</param>
<param name="value">The cursor value to set.</param>
private static void SetOldCursor(DependencyObject source, object value)
{
source.SetValue(OldCursorProperty, value);
}
<param name="source">The object to get the old cursor for.</param>
private static Cursor GetOldCursor(DependencyObject source)
{
return source.GetValue(OldCursorProperty) as Cursor;
}
}