Указатель.Текущий против этого.Указатель



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



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



если я поставил this.Cursor to Cursors.WaitCursor в событии нажатия кнопки на form1 и show form2 курсор ожидания отображается только на form1, а курсор по умолчанию находится на form2, который ожидается. Так что, я до сих пор не знаю, что Cursor.Current делает.

595   7  

7 ответов:

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

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

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

курсор не меняется. Чтобы ударить это в форму, вам нужно будет использовать Указатель.И ток тоже. Вот небольшой вспомогательный класс, чтобы сделать его легко:

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);
  }
}

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

На самом деле, если вы хотите использовать песочные часы из другого потока, который вернет вам исключение перекрестной резьбы, потому что вы пытаетесь получить доступ к 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);
    }
}

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

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

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

этого.курсор = курсоры.Waitcursor

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

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

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

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

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

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

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

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

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

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

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

From VB.net VS 2012

Windows.Forms.Cursor.Current = Cursors.Default

Comments

    Ничего не найдено.