65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight OverrideCursor

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (2投票s)

2009年4月16日

CPOL

1分钟阅读

viewsIcon

23804

WPF 中一个非常棒的功能是使用 Mouse.OverrideCursor 为整个应用程序设置光标。

WPF 中一个非常棒的功能是使用 Mouse.OverrideCursor 为整个应用程序设置光标。例如,如果你的应用程序需要执行一个耗时操作,你可以将光标更改为等待光标,直到操作完成。通常,你会像这样操作:

public void DoAReallyLongOperation()
{
  Cursor savedCursor = Mouse.OverrideCursor;
  try
  {
    PerformMyLengthyOperation();
  }
  finally
  {
    Mouse.OverrideCursor = savedCursor
  }
}

到目前为止一切都很好。现在,你肯定会跑到你的 Silverlight 应用程序中,对耗时操作执行完全相同的操作,对吧?毕竟,Silverlight 是 WPF 的轻量级版本,所以肯定可以使用这个功能。

然而,事实并非如此。Silverlight 不支持 OverrideCursor,但添加它应该不难,对吧?实际上,添加 OverrideCursor 并没有你想象的那么容易。例如,如果你将页面上的光标更改为等待光标,当鼠标移动到文本框上时,它仍然会是 IBeam (文本光标)。这意味着你的代码需要遍历视觉树,查找所有子元素,并将光标设置为新的光标。

编辑自从我今天早上发布这篇文章以来,有人提出了一种需要解决的边缘情况。基本上,代码需要能够将文本框重置回 IBeam ,假设 OverrideCursor 被重置。

以下类提供了一个附加属性,应该可以很好地解决这个问题。

/// <summary>
/// Mouse handling class to simulate the OverrideCursor functionality in WPF.
/// </summary>
public class Mouse : DependencyObject
{
  #region Members
  private static Cursor _oldCursor;
  private static bool _isResetting = false;
  private static Cursor _overrideCursor;
  #endregion
  /// <summary>
  /// Recursively traverse the visual tree, setting the cursor as appropriate.
  /// </summary>
  ///
<param name="current">The element to iterate over.</param>
  ///
<param name="cursor">The cursor to set to.</param>
  /// <remarks>
  /// If the new cursor is the same as the stored original cursor,
  /// then we assume that this is a reset operation taking place.
  /// At this point, we reset the cursor to the original for the element,
  /// irrespective of what the Cursor states.
  /// </remarks>
  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 this is a reset, then get the old cursor reference
        // back so that we can use this.
        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);
      }
    }
  }
  /// <summary>
  /// The OverrideCursor attached property.
  /// </summary>
  public static readonly DependencyProperty OverrideCursorProperty =
    DependencyProperty.RegisterAttached("OverrideCursor",
    typeof(Cursor),
    typeof(UserControl),
    new PropertyMetadata(null, OnCursorChanged));
  /// <summary>
  /// The OldCursor attached property.
  /// </summary>
  private static readonly DependencyProperty OldCursorProperty =
    DependencyProperty.RegisterAttached("OldCursor",
    typeof(Cursor),
    typeof(UserControl),
    new PropertyMetadata(null));
  /// <summary>
  /// Called when the cursor changes.
  /// </summary>
  private static void OnCursorChanged(DependencyObject source,
    DependencyPropertyChangedEventArgs e)
  {
    if (!(source is FrameworkElement))
      return;
    // If the "old" cursor is the same as the "new" cursor, the
    // code will reset each elements cursor back to its original value.
    _isResetting = (_oldCursor == e.NewValue);
    if (!_isResetting)
    {
      _oldCursor = e.OldValue as Cursor;
    }
    TraverseVisualTree(source, e.NewValue as Cursor);
  }
  /// <summary>
  /// Get the override cursor.
  /// </summary>
  ///
<param name="source">The object to get the override cursor for.</param>
  /// <returns>The populated override cursor.</returns>
  public static Cursor GetOverrideCursor(DependencyObject source)
  {
    return source.GetValue(OverrideCursorProperty) as Cursor;
  }
  /// <summary>
  /// Set the override cursor.
  /// </summary>
  ///
<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);
  }
  /// <summary>
  /// Set the old cursor.
  /// </summary>
  ///
<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);
  }
  /// <summary>
  /// Get the old cursor.
  /// </summary>
  ///
<param name="source">The object to get the old cursor for.</param>
  /// <returns>The populated old cursor.</returns>
  private static Cursor GetOldCursor(DependencyObject source)
  {
    return source.GetValue(OldCursorProperty) as Cursor;
  }
}
© . All rights reserved.