Курсор. Текущий против этого. Курсор - PullRequest
54 голосов
/ 19 ноября 2008

Есть ли разница между Cursor.Current и this.Cursor (где this - WinForm) в .Net? Я всегда использовал this.Cursor и мне очень повезло, но я недавно начал использовать CodeRush и просто встроил некоторый код в блок «Wait Cursor», а CodeRush использовал свойство Cursor.Current. Я видел в Интернете и на работе, где у других программистов были некоторые проблемы со свойством Cursor.Current. Это просто заставило меня задуматься, есть ли разница в двух. Заранее спасибо.

Я сделал небольшой тест. У меня есть две формы. Я нажимаю кнопку на форме form1, устанавливаю для свойства Cursor.Current значение Cursors.WaitCursor, а затем показываю form2. Курсор не меняется ни на одной из форм. Остается Cursors.Default (указатель) курсора.

Если я установлю this.Cursor на Cursors.WaitCursor в событии нажатия кнопки на форме 1 и покажу форму 2, курсор ожидания отображается только на форме 1, а курсор по умолчанию находится на форме 2, что ожидается. Итак, я до сих пор не знаю, что делает Cursor.Current.

Ответы [ 7 ]

87 голосов
/ 19 ноября 2008

Windows отправляет окну, в котором находится курсор мыши, сообщение WM_SETCURSOR, давая ему возможность изменить форму курсора. Элемент управления типа TextBox использует это преимущество, превращая курсор в I-бар. Свойство Control.Cursor определяет, какая фигура будет использоваться.

Свойство Cursor.Current меняет форму напрямую, не дожидаясь ответа WM_SETCURSOR. В большинстве случаев такая форма вряд ли сохранится надолго. Как только пользователь перемещает мышь, WM_SETCURSOR меняет ее на Control.Cursor.

Свойство 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;
}

Курсор никогда не меняется. Чтобы привести это в порядок, вам также нужно использовать 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);
  }
}
10 голосов
/ 19 ноября 2008

Я считаю, что Cursor.Current - это курсор мыши, используемый в данный момент (независимо от того, где он находится на экране), тогда как this.Cursor - это курсор, на который он будет установлен, когда мышь будет проходить над окном.

6 голосов
/ 15 декабря 2011

На самом деле, если вы хотите использовать HourGlass из другого потока, который вернет вам исключение перекрестного потока, потому что вы пытаетесь получить доступ к f.Handle из потока, отличного от того, который изначально был создан. Используйте GetForegroundWindow () вместо user32.dll.

[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);
    }
}
5 голосов
/ 19 ноября 2008

this.Cursor - курсор, который будет использоваться, когда мышь находится над окном, на которое указывает this. Cursor.Current - текущий курсор мыши, который может отличаться от this.Cursor, если мышь находится в другом окне.

2 голосов
/ 30 апреля 2016

Я заметил интересную вещь об установке курсоров, поэтому я хотел бы устранить некоторые недоразумения, которые у меня были раньше, и я надеюсь, что это может помочь и другим:

При попытке установить курсор формы с помощью

this.cursor = Cursors.Waitcursor

вы фактически устанавливаете курсор для элемента управления, а не всю форму, поскольку курсор является свойством класса Control.

Также, конечно, курсор будет изменен на данный курсор только тогда, когда мышь фактически находится над фактическим элементом управления (явно область формы)

Как уже сказал Ганс Пассант:

Windows отправляет окно, содержащее курсор мыши, Сообщение WM_SETCURSOR, дающее возможность изменить курсор форма

Я не знаю, отправляет ли Windows сообщения непосредственно элементам управления или же форма передает эти сообщения своим дочерним элементам управления в зависимости от положения мыши, я, скорее всего, догадываюсь о первом методе с тех пор, как я извлек сообщения с переопределением WndProc элемента управления формой, например, когда я находился над текстовым полем, форма не обрабатывала никаких сообщений. (пожалуйста, кто-нибудь прояснит это)

По сути, мое предложение было бы отказаться от использования this.cursor и придерживаться this.usewaitcursor, поскольку это изменяет свойство курсора на waitcursor для всех дочерних элементов управления.

Проблема с этим также та же, что и с уровнем приложения Application.usewaitcursor, пока вы не перешли через формы / формы с помощью курсора, никакое сообщение WM_SETCURSOR не отправляется окнами, поэтому, если вы запускаете синхронную операцию, отнимающую много времени перед тем, как навести курсор мыши на область формы, форма может обработать такое сообщение только после завершения трудоемкой синхронной операции.

(я бы вообще не советовал запускать трудоемкие задачи в потоке пользовательского интерфейса, в основном это является причиной проблемы)

Я немного улучшил ответ Ханса Пассанта, так что песочные часы можно установить либо на уровне приложения, либо на уровне формы, также избегая исключения 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
}

или вы можете инициализировать локальную переменную в виде:

public readonly HourGlass hourglass;

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

и использовать его позже в блоке try catch наконец

0 голосов
/ 12 марта 2015

Из VB.net VS 2012

Windows.Forms.Cursor.Current = Cursors.Default
0 голосов
/ 15 февраля 2015

Это прекрасно работает для меня, когда LongRunningOperation () обрабатывает сообщения.

private void btnDoLongRunningOperation_Click(object sender, System.EventArgs e)
{
    this.Cursor = Cursors.WaitCursor;
    LongRunningOperation();
    this.Cursor = Cursors.Arrow;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...