【问题标题】:Binding mouse cursor to button property in WPF将鼠标光标绑定到 WPF 中的按钮属性
【发布时间】:2012-05-08 00:05:41
【问题描述】:

我有一个按钮需要很长时间才能完成其功能,并且由于长时间等待(5 秒),应用程序似乎已停止。所以在长时间运行的函数之前我放了Cursor = Cursors.Wait,在函数之后我放了Cursor = Cursors.Arrow,一切正常。

但我认为这是一种非常糟糕的方式来做这样的事情。

这就是为什么我想知道是否可以将光标绑定到按钮的属性,以便在按钮执行其功能时光标会发生变化。

【问题讨论】:

    标签: c# wpf binding


    【解决方案1】:

    好的,六年后。 1. 看看 async-await 构造,它很简单,你的硬任务将在非 UI 线程中执行。 2. 由于您逐步完成了前一个,您可以将一些 bool 属性放入您的模型中,例如 actionExecuting 并在您完成任务之前/之后设置/取消设置它。然后在视图中,您可以将主容器的Cursor 属性绑定到actionExecuting。要实现这一点,您需要实现IValueConverter。例如(查看命名空间):

    namespace YourApp.Util.Converters
    {
        [ValueConversion(typeof(bool), typeof(Cursor))]
        public class BoolToCursorConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                var val = (bool)value;
                if (val)
                    return Cursors.WaitCursor;
                return Cursors.Arrow;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter,
                System.Globalization.CultureInfo culture)
            {
                throw new NotSupportedException();
            }
        }
    }
    

    然后您要添加此转换器以在 Window.Resources 或您的资源字典中查看,例如:

    <Window x:Class="YourApp.MainWindow"
            <!-- other namespaces -->
            xmlns:c="clr-namespace:YourApp.Util.Converters">
    
    <Window.Resources>
            <c:BoolToCursorConverter x:Key="BoolToCursorConverter"></c:BoolToCursorConverter>
        </Window.Resources>
    

    而且你可以像这样使用它

    <Grid Cursor="{Binding actionExecuting, Converter={StaticResource BoolToCursorConverter}}">
    

    【讨论】:

      【解决方案2】:

      你为什么不使用后台工作人员来执行长时间运行的功能(可能是生产/消费者模式)?在我看来,这是最好的方式。您还可以通过进度条通知用户他的请求状态。

      【讨论】:

      • 我曾想过使用线程,但它不仅仅是一个按钮。有很多这样的。是不是和在函数结束前后放那两行代码其实是一样的?
      • 如果没有关于您的程序的任何进一步信息,我无法给您一个满意的答案。但也许你可以使用线程池来解决这个问题。
      • 我会调查的。但是您知道是否有办法将 cursor 属性绑定到 button.isfocused 属性(例如)?我认为我不能对光标这样做,因为它不是依赖对象
      【解决方案3】:

      我能想到的最简单的事情是创建一个实现 IDisposable 的类并在构造函数中更改等待光标,然后在 Dispose 方法中将其还原。这样可以确保如果在其包装的代码执行时抛出异常,则光标不会作为等待光标卡住...

      public class WaitCursor : IDisposable
      {
          private Cursor m_defaultCursor = null;
          public WaitCursor()
          {
              m_defaultCursor = Cursors.Current;
              Cursors.Current = Cursors.WaitCursor;
              Application.UseWaitCursor = true;
          }
      
          public void Dispose()
          {
              Cursors.Current = m_defaultCursor;
              Application.UseWaitCursor = false;
          }
      }
      

      然后你可以用 using 语句包装你长时间运行的代码......

      using (var waitCursor = new WaitCursor())
      {
          // some long running code...
      }
      

      这让未来的开发人员清楚地知道,打包的代码也可能需要一段时间

      【讨论】:

        【解决方案4】:

        理论上,您可以在某处创建一个依赖属性,以便在按钮状态更改时设置鼠标光标。但是,如果您确实在按钮单击处理程序内部进行工作,则它不太可能做任何事情,因为您的 UI 线程需要调度依赖对象来更新。此外,如果您阻塞 UI 线程,则在任务完成之前,您不会在视觉上看到按钮“松开”。另外,您如何将它绑定到一个打开的、可能正在更改的按钮集?这听起来不是一个令人满意的解决方案。

        我认为在 WPF 应用程序中处理此类情况的最佳方法是在后台线程(或线程池)中运行长时间运行的任务,当它完成时会将其结果发送回 UI 线程。发生这种情况时,您可以同时保持 UI 完全交互,或者使用等待光标(并明确禁用您的 UI),或者使用“正在进行的工作,请等待 [取消按钮]”对话框阻止它,如果你想给个取消选项。

        在后台线程中执行操作也有助于让您的 WPF 应用程序窗口响应移动/最小化/最大化等窗口管理操作。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-20
          • 2012-03-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-01-07
          相关资源
          最近更新 更多