C# Cursor.Current 与 this.Cursor
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/302663/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cursor.Current vs. this.Cursor
提问by Keith
Is there a difference between Cursor.Current
and this.Cursor
(where this
is a WinForm) in .Net? I've always used this.Cursor
and have had very good luck with it but I've recently started using CodeRush and just embedded some code in a "Wait Cursor" block and CodeRush used the Cursor.Current
property. I've seen on the Internet and at work where other programmers have had some problems with the Cursor.Current
property. It just got me to wondering if there is a difference in the two. Thanks in advance.
.Net 中的Cursor.Current
和this.Cursor
(this
WinForm 在哪里)之间有区别吗?我一直在使用它this.Cursor
并且运气很好,但我最近开始使用 CodeRush,只是在“等待光标”块中嵌入了一些代码,而 CodeRush 使用了该Cursor.Current
属性。我在 Internet 上和工作中看到其他程序员对该Cursor.Current
属性有一些问题。这只是让我想知道两者是否有区别。提前致谢。
I did a little test. I have two winforms. I click a button on form1, set the Cursor.Current
property to Cursors.WaitCursor
and then show form2. The cursor doesn't change on either form. It remains Cursors.Default
(pointer) cursor.
我做了一个小测试。我有两个winform。我单击 form1 上的一个按钮,将Cursor.Current
属性设置为Cursors.WaitCursor
然后显示 form2。两种形式的光标都不会改变。它仍然是Cursors.Default
(指针)光标。
If I set this.Cursor
to Cursors.WaitCursor
in the button click event on form1 and show form2, the wait cursor only shows on form1 and the default cursor is on form2 which is expected. So, I still don't know what Cursor.Current
does.
如果我在 form1 上的按钮单击事件中设置this.Cursor
为Cursors.WaitCursor
并显示 form2,则等待光标仅显示在 form1 上,默认光标位于 form2 上,这是预期的。所以,我仍然不知道是什么Cursor.Current
。
采纳答案by Hans Passant
Windows sends the window that contains the mouse cursor the WM_SETCURSOR message, giving it an opportunity to change the cursor shape. A control like TextBox takes advantage of that, changing the cursor into a I-bar. The Control.Cursor property determines what shape will be used.
Windows 向包含鼠标光标的窗口发送 WM_SETCURSOR 消息,使其有机会更改光标形状。像 TextBox 这样的控件利用了这一点,将光标更改为 I-bar。Control.Cursor 属性确定将使用什么形状。
The Cursor.Current property changes the shape directly, without waiting for a WM_SETCURSOR response. In most cases, that shape is unlikely to survive for long. As soon as the user moves the mouse, WM_SETCURSOR changes it back to Control.Cursor.
Cursor.Current 属性直接更改形状,无需等待 WM_SETCURSOR 响应。在大多数情况下,这种形状不太可能长期存在。一旦用户移动鼠标,WM_SETCURSOR 就会将其更改回 Control.Cursor。
The UseWaitCursor property was added in .NET 2.0 to make it easier to display an hourglass. Unfortunately, it doesn't work very well. It requires a WM_SETCURSOR message to change the shape and that won't happen when you set the property to true and then do something that takes a while. Try this code for example:
UseWaitCursor 属性是在 .NET 2.0 中添加的,以便更容易地显示沙漏。不幸的是,它不能很好地工作。它需要 WM_SETCURSOR 消息来更改形状,并且当您将该属性设置为 true 然后执行一些需要一段时间的操作时不会发生这种情况。试试这个代码,例如:
private void button1_Click(object sender, EventArgs e) {
this.UseWaitCursor = true;
System.Threading.Thread.Sleep(3000);
this.UseWaitCursor = false;
}
The cursor never changes. To whack that into shape, you'll need to use Cursor.Current as well. Here is a little helper class to make it easy:
光标永远不会改变。为了使之成形,您还需要使用 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);
}
And use it like this:
并像这样使用它:
private void button1_Click(object sender, EventArgs e) {
using (new HourGlass()) {
System.Threading.Thread.Sleep(3000);
}
}
回答by James Curran
I believe that Cursor.Current is the mouse cursor currently being used (regardless of where it is on the screen), while this.Cursor is the cursor it will be set to, when the mouse passes over your window.
我相信 Cursor.Current 是当前使用的鼠标光标(无论它在屏幕上的哪个位置),而 this.Cursor 是当鼠标经过您的窗口时将设置为的光标。
回答by Joel Coehoorn
this.Cursor
is the cursor that will be used when the mouse is over the window referred to by this
. Cursor.Current
is the current mouse cursor, which might be different from this.Cursor
if the mouse is over a different window.
this.Cursor
是当鼠标悬停在由 引用的窗口上时将使用的光标this
。 Cursor.Current
是当前鼠标光标,这可能this.Cursor
与鼠标在不同窗口上的情况不同。
回答by wa?dis iljuczonok
Actually if you would like to use HourGlass from another thread that will give you back cross-threading exception because you are trying to access f.Handle from different thread than form was originally created. Use GetForegroundWindow() instead from user32.dll.
实际上,如果您想从另一个线程使用 HourGlass,它会给您返回跨线程异常,因为您试图从与表单最初创建的线程不同的线程访问 f.Handle。使用 GetForegroundWindow() 代替 user32.dll。
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
and then
进而
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);
}
}
回答by bootsn
This works great for me when the LongRunningOperation() is processing messages.
当 LongRunningOperation() 处理消息时,这对我很有用。
private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
this.Cursor = Cursors.WaitCursor;
LongRunningOperation();
this.Cursor = Cursors.Arrow;
}
回答by Elian
From VB.net VS 2012
来自 VB.net VS 2012
Windows.Forms.Cursor.Current = Cursors.Default
回答by Attila Horváth
I have noticed an interesting thing about setting cursors, so I would like to clear some misunderstandings that I myself had before and I hope it may help others too:
我注意到一个关于设置游标的有趣的事情,所以我想澄清一下我自己之前的一些误解,希望它也可以帮助其他人:
When you try to set a form's cursor by using
当您尝试使用设置表单的光标时
this.cursor = Cursors.Waitcursor
this.cursor = Cursors.Waitcursor
you actually set the cursor for the control and not the whole form since cursor is property of the Control class.
您实际上为控件而不是整个表单设置了光标,因为光标是 Control 类的属性。
Also of course the cursor will only be changed to the given cursor when the mouse is actually over the actual control (explicitly the form's area)
当然,只有当鼠标实际位于实际控件上时,光标才会更改为给定的光标(明确表示表单的区域)
As Hans Passant has already stated that:
正如 Hans Passant 已经指出的那样:
Windows sends the window that contains the mouse cursor the WM_SETCURSOR message, giving it an opportunity to change the cursor shape
Windows 向包含鼠标光标的窗口发送 WM_SETCURSOR 消息,使其有机会更改光标形状
I don't know if windows sends messages directly to controls or if the form relays those messages to it's child controls based on mouse position, I'd most likely guess on the first method since when i fetched the messages with overriding WndProc of the form control, when i was over the textbox for example, the form didn't process any messages. (please someone give clarity on this)
我不知道 windows 是否直接向控件发送消息,或者表单是否根据鼠标位置将这些消息中继到它的子控件,我很可能会猜测第一种方法,因为当我使用覆盖表单的 WndProc 获取消息时控件,例如,当我在文本框上方时,表单没有处理任何消息。(请有人澄清这一点)
Basically my suggestion would be to reside from using this.cursor also and stick to this.usewaitcursor, since that changes the cursor property to waitcursor for all child controls.
基本上我的建议是也不要使用 this.cursor 并坚持使用 this.usewaitcursor,因为这会将所有子控件的光标属性更改为 waitcursor。
The problem with this is also the same as with the application level Application.usewaitcursor, while you are not over the form/forms with your cursor no WM_SETCURSOR message is being sent by windows, so if you start a time consuming synchronous operation before moving your mouse over the form's area, the form can only process such message when the time consuming synchronous operation finishes.
这个问题也与应用程序级 Application.usewaitcursor 相同,当您没有使用光标在表单/表单上时,Windows 不会发送 WM_SETCURSOR 消息,因此如果您在移动之前启动耗时的同步操作将鼠标悬停在表单区域上,表单只能在耗时的同步操作完成后处理此类消息。
(I would not suggest running time consuming tasks in the UI thread at all, mainly this is what is causing the issue here)
(我根本不建议在 UI 线程中运行耗时的任务,这主要是导致问题的原因)
I made a little improvement on Hans Passant's answer, so the hourglass can be either set on application level or form level, also avoiding InvalidOperationException from cross threaded operation calls:
我对 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);
}
To use it on application level:
要在应用程序级别使用它:
try
{
HourGlass.ApplicationEnabled = true;
//time consuming synchronous task
}
finally
{
HourGlass.ApplicationEnabled = false;
}
For using it on form level you can either use for the current active form:
要在表单级别使用它,您可以将其用于当前活动表单:
using (new HourGlass())
{
//time consuming synchronous task
}
or you can initialize a local variable in the form like this:
或者你可以像这样初始化一个局部变量:
public readonly HourGlass hourglass;
public Form1()
{
InitializeComponent();
hourglass = new HourGlass(this, false);
}
and use it later in a try catch finally block
稍后在 try catch finally 块中使用它