Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/301.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Cursor.Current与this.Cursor_C#_.net_Winforms_Cursor_Cursor.current - Fatal编程技术网

C# Cursor.Current与this.Cursor

C# Cursor.Current与this.Cursor,c#,.net,winforms,cursor,cursor.current,C#,.net,Winforms,Cursor,Cursor.current,Net中的Cursor.Current和this.Cursor(其中this是WinForm)之间是否存在差异?我一直使用this.Cursor,而且运气很好,但最近我开始使用CodeRush,只是在“Wait Cursor”块中嵌入了一些代码,CodeRush使用了Cursor.Current属性。我在网上和工作中看到,其他程序员在Cursor.Current属性方面遇到了一些问题。这让我想知道这两者是否有区别。提前谢谢 我做了一个小测试。我有两个表格。我单击form1上的一个按钮,将Curs

Net中的
Cursor.Current
this.Cursor
(其中
this
是WinForm)之间是否存在差异?我一直使用
this.Cursor
,而且运气很好,但最近我开始使用CodeRush,只是在“Wait Cursor”块中嵌入了一些代码,CodeRush使用了
Cursor.Current
属性。我在网上和工作中看到,其他程序员在
Cursor.Current
属性方面遇到了一些问题。这让我想知道这两者是否有区别。提前谢谢

我做了一个小测试。我有两个表格。我单击form1上的一个按钮,将
Cursor.Current
属性设置为
Cursors.WaitCursor
,然后显示form2。两种形式上的光标都不会改变。它仍然是
光标。默认为
(指针)光标


如果我在form1和show form2上的按钮单击事件中将
this.Cursor
设置为
Cursors.WaitCursor
,则等待光标仅在form1上显示,默认光标在form2上,这是预期的。所以,我仍然不知道Cursor.Current是做什么的。

我相信Cursor.Current是当前正在使用的鼠标光标(不管它在屏幕上的什么位置),而this.Cursor是它将被设置的光标,当鼠标经过您的窗口时。

此。光标
是鼠标位于
所指窗口上时将使用的光标
Cursor.Current
是当前鼠标光标,可能与此不同。如果鼠标位于不同的窗口上,则光标

Windows向包含鼠标光标的窗口发送WM_SETCURSOR消息,使其有机会更改光标形状。像TextBox这样的控件利用了这一点,将光标更改为I-bar。Control.Cursor属性确定将使用的形状

Cursor.Current属性直接更改形状,而无需等待WM_SETCURSOR响应。在大多数情况下,这种形状不太可能长期存在。一旦用户移动鼠标,WM_SETCURSOR就会将其更改回Control.Cursor

在.NET2.0中添加了UseWaitCursor属性,以使沙漏显示更容易。不幸的是,它工作得不太好。它需要一个WM_SETCURSOR消息来更改形状,当您将属性设置为true,然后执行一些需要一段时间的操作时,这种情况不会发生。请尝试以下代码,例如:

private void button1_Click(object sender, EventArgs e) {
  this.UseWaitCursor = true;
  System.Threading.Thread.Sleep(3000);
  this.UseWaitCursor = false;
}
光标永远不会改变。要使其成形,还需要使用Cursor.Current。下面是一个简单的帮助器类:

using System;
using System.Windows.Forms;

public class HourGlass : IDisposable {
  public HourGlass() {
    Enabled = true;
  }
  public void Dispose() {
    Enabled = false;
  }
  public static bool Enabled {
    get { return Application.UseWaitCursor; }
    set {
      if (value == Application.UseWaitCursor) return;
      Application.UseWaitCursor = value;
      Form f = Form.ActiveForm;
      if (f != null && f.Handle != IntPtr.Zero)   // Send WM_SETCURSOR
        SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1);
    }
  }
  [System.Runtime.InteropServices.DllImport("user32.dll")]
  private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
然后像这样使用它:

private void button1_Click(object sender, EventArgs e) {
  using (new HourGlass()) {
    System.Threading.Thread.Sleep(3000);
  }
}
public readonly HourGlass hourglass;

public Form1()
{
    InitializeComponent();
    hourglass = new HourGlass(this, false);
}

实际上,若你们想从另一个线程中使用沙漏,那个么它将返回交叉线程异常,因为你们正试图从不同于最初创建窗体的线程中访问f.Handle。从user32.dll使用GetForegroundWindow()代替

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
然后

public static bool Enabled
{
    get
    {
        return Application.UseWaitCursor;
    }

    set
    {
        if (value == Application.UseWaitCursor)
        {
            return;
        }

        Application.UseWaitCursor = value;
        var handle = GetForegroundWindow();
        SendMessage(handle, 0x20, handle, (IntPtr)1);
    }
}

当LongRunningOperation()处理消息时,这对我来说非常有用

private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
    this.Cursor = Cursors.WaitCursor;
    LongRunningOperation();
    this.Cursor = Cursors.Arrow;
}
从VB.net到2012

Windows.Forms.Cursor.Current = Cursors.Default

我注意到关于设置游标的一件有趣的事情,所以我想澄清我自己以前的一些误解,我希望这也能帮助其他人:

当您尝试使用设置窗体的光标时

this.cursor=Cursors.Waitcursor

实际上是为控件而不是整个表单设置游标,因为游标是控件类的属性

当然,只有当鼠标实际位于实际控件上时(明确表示窗体的区域),光标才会更改为给定的光标

正如Hans Passant所说:


Windows发送包含鼠标光标的窗口 WM_SETCURSOR消息,使其有机会更改光标 形状

我不知道windows是否直接向控件发送消息,或者窗体是否基于鼠标位置将这些消息转发给它的子控件,我很可能会猜测第一种方法,因为当我使用重写窗体控件的WndProc获取消息时,例如,当我在文本框上时,窗体没有处理任何消息。(请有人对此作出澄清)

基本上,我的建议是也使用this.cursor并坚持使用this.usewaitcursor,因为这会将所有子控件的cursor属性更改为waitcursor

此问题与应用程序级application.usewaitcursor的问题相同,当您未使用光标在窗体上时,windows不会发送WM_SETCURSOR消息,因此如果在将鼠标移到窗体区域之前启动耗时的同步操作,表单只能在耗时的同步操作完成时处理此类消息

(我不建议在UI线程中运行耗时的任务,这主要是造成问题的原因)

我对Hans Passant的答案做了一些改进,因此沙漏可以设置在应用程序级或表单级,也可以避免交叉线程操作调用的InvalidOperationException:

using System;
using System.Windows.Forms;

public class HourGlass : IDisposable
{
    public static bool ApplicationEnabled
    {
        get{ return Application.UseWaitCursor; }
        set
        {
            Form activeFrom = Form.ActiveForm;
            if (activeFrom == null || ApplicationEnabled == value) return;
            if (ApplicationEnabled == value)return;
            Application.UseWaitCursor = (bool)value;

            if (activeFrom.InvokeRequired)
            {
                activeFrom.BeginInvoke(new Action(() =>
                {
                    if (activeFrom.Handle != IntPtr.Zero)
                    SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
                }));
            }
            else
            {
                if (activeFrom.Handle != IntPtr.Zero)
                SendMessage(activeFrom.Handle, 0x20, activeFrom.Handle, (IntPtr)1); // Send WM_SETCURSOR
            }
        }
    }

    private Form f;

    public HourGlass() 
    {
        this.f = Form.ActiveForm;

        if (f == null)
        {
            throw new ArgumentException();
        }
        Enabled = true;
    }

    public HourGlass(bool enabled)
    {
        this.f = Form.ActiveForm;

        if (f == null)
        {
            throw new ArgumentException();
        }
        Enabled = enabled;
    }

    public HourGlass(Form f, bool enabled)
    {
        this.f = f;

        if (f == null)
        {
            throw new ArgumentException();
        }
        Enabled = enabled;
    }

    public HourGlass(Form f)
    {
        this.f = f;

        if (f == null)
        {
            throw new ArgumentException();
        }

        Enabled = true;
    }

    public void Dispose()
    {
        Enabled = false;
    }

    public bool Enabled
    {
        get { return f.UseWaitCursor; }
        set
        {
            if (f == null || Enabled == value) return;
            if (Application.UseWaitCursor == true && value == false) return;

            f.UseWaitCursor = (bool)value;

            if(f.InvokeRequired)
            {
                f.BeginInvoke(new Action(()=>
                {
                    if (f.Handle != IntPtr.Zero)
                    SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
                }));
            }
            else
            {
                if (f.Handle != IntPtr.Zero)
                SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1); // Send WM_SETCURSOR
            }
        }
    }

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
}
要在应用程序级别使用它,请执行以下操作:

try
{
  HourGlass.ApplicationEnabled = true;
  //time consuming synchronous task
}
finally
{
  HourGlass.ApplicationEnabled = false;
}
要在表单级别使用它,您可以对当前活动表单使用:

using (new HourGlass())
{
  //time consuming synchronous task
}
或者,您可以按如下形式初始化局部变量:

private void button1_Click(object sender, EventArgs e) {
  using (new HourGlass()) {
    System.Threading.Thread.Sleep(3000);
  }
}
public readonly HourGlass hourglass;

public Form1()
{
    InitializeComponent();
    hourglass = new HourGlass(this, false);
}

稍后在try-catch-finally块中使用它

我遇到了一个案例,当我将它与启动屏幕结合使用时,会导致InvalidOperationException-“交叉线程操作无效”。添加一个!f、 f之间需要调用=null和f。句柄=null解决了这个问题。这对我来说非常有用,但根据ReSharper的说法,这行中的“表达式总是正确的”:if(f!=null&&f.Handle!=null)//Send WM_SETCURSORThis是一个很棒的助手类。在没有其他操作的情况下工作。如果在缓慢的代码完成运行后无法让光标更新,则说明您做错了。您可能需要更改上述代码