2008-11-20 31 views
103

Mở nhiều của usercontrols của tôi, tôi thay đổi con trỏ bằng cách sử dụngThay đổi con trỏ trong WPF đôi khi làm việc, đôi khi không

this.Cursor = Cursors.Wait; 

khi tôi bấm vào một cái gì đó.

Bây giờ tôi muốn làm điều tương tự trên trang WPF khi nhấp vào nút. Khi tôi di chuột qua nút của tôi, con trỏ sẽ thay đổi thành bàn tay, nhưng khi tôi nhấp vào nút đó, con trỏ sẽ không thay đổi thành con trỏ chờ. Tôi tự hỏi nếu điều này có cái gì để làm với thực tế rằng đó là một nút, hoặc bởi vì đây là một trang và không phải là một usercontrol? Điều này có vẻ như hành vi kỳ lạ.

Trả lời

176

Bạn có cần con trỏ là con trỏ "chờ" khi nó nằm trên trang/điều khiển người dùng cụ thể không? Nếu không, tôi muốn đề nghị sử dụng Mouse.OverrideCursor:

Mouse.OverrideCursor = Cursors.Wait; 
try 
{ 
    // do stuff 
} 
finally 
{ 
    Mouse.OverrideCursor = null; 
} 

này ghi đè con trỏ cho ứng dụng của bạn chứ không phải chỉ dành riêng cho một phần của giao diện người dùng của nó, vì vậy vấn đề bạn đang mô tả biến mất.

+0

Tương tự như [answer] (http://stackoverflow.com/a/8211178/448232) của riêng mình, ngày 3 năm sau (gần như chính xác!). Tôi thích câu trả lời trong câu hỏi này, nhưng câu trả lời đơn giản nhất luôn hấp dẫn nhất :) –

+0

Giải pháp này sẽ thay đổi con trỏ thành con trỏ "chờ" nhưng nó sẽ không tắt bất kỳ đầu vào chuột nào nữa. Tôi đã thử sử dụng giải pháp này và mặc dù con chuột đã thay đổi thành con trỏ đợi nhưng tôi vẫn có thể nhấp vào bất kỳ phần tử giao diện người dùng nào trong ứng dụng WPF của mình mà không gặp bất kỳ sự cố nào. Bất kỳ ý tưởng làm thế nào tôi có thể ngăn chặn người dùng thực sự bằng cách sử dụng con chuột trong con trỏ chờ đang hoạt động? –

+1

Cũ như nó được chấp nhận như nó là, nó không phải là câu trả lời đúng. Việc ghi đè con trỏ ứng dụng khác với việc ghi đè con trỏ điều khiển (và con trỏ thứ hai có vấn đề trong WPF ở bên phải). Việc ghi đè con trỏ ứng dụng có thể có các hiệu ứng phụ khó chịu, ví dụ: hộp thông báo bật lên (lỗi) có thể bị buộc sử dụng cùng con trỏ bị ghi đè sai trong khi ý định chỉ ghi đè khi chuột di chuột qua điều khiển thực và hoạt động. –

57

Một cách chúng tôi làm điều này trong ứng dụng của chúng tôi là sử dụng IDisposable và sau đó với using(){} khối để đảm bảo con trỏ được đặt lại khi hoàn tất.

public class OverrideCursor : IDisposable 
{ 

    public OverrideCursor(Cursor changeToCursor) 
    { 
    Mouse.OverrideCursor = changeToCursor; 
    } 

    #region IDisposable Members 

    public void Dispose() 
    { 
    Mouse.OverrideCursor = null; 
    } 

    #endregion 
} 

và sau đó trong mã của bạn:

using (OverrideCursor cursor = new OverrideCursor(Cursors.Wait)) 
{ 
    // Do work... 
} 

Các override sẽ kết thúc khi một trong hai: sự kết thúc của câu lệnh using là đạt hoặc; nếu một ngoại lệ được ném và kiểm soát lá khối lệnh trước khi kết thúc câu lệnh.

Cập nhật

Để ngăn chặn con trỏ nhấp nháy bạn có thể làm:

public class OverrideCursor : IDisposable 
{ 
    static Stack<Cursor> s_Stack = new Stack<Cursor>(); 

    public OverrideCursor(Cursor changeToCursor) 
    { 
    s_Stack.Push(changeToCursor); 

    if (Mouse.OverrideCursor != changeToCursor) 
     Mouse.OverrideCursor = changeToCursor; 
    } 

    public void Dispose() 
    { 
    s_Stack.Pop(); 

    Cursor cursor = s_Stack.Count > 0 ? s_Stack.Peek() : null; 

    if (cursor != Mouse.OverrideCursor) 
     Mouse.OverrideCursor = cursor; 
    } 

} 
+1

Chạm đẹp vào ngăn xếp. -john – jschroedl

+0

Cảm ơn John. Nó rất hữu ích khi bạn bắt đầu lồng các thay đổi con trỏ khi có nhiều điểm vào. Cũng lưu ý các kiểm tra để ngăn con trỏ nhấp nháy. Nó tương đương với IL cơ bản giống như câu trả lời đã chọn. – Dennis

+2

Giải pháp tốt với phần sử dụng. Tôi thực sự đã viết chính xác như vậy trong một số dự án của chúng tôi (không có ngăn xếp, đó là). Một điều bạn có thể đơn giản hóa trong cách sử dụng là viết: sử dụng (OverrideCursor mới (Cursors.Wait)) {// do stuff} thay vì gán cho nó một biến mà bạn có thể sẽ không sử dụng. – Olli

36

Bạn có thể sử dụng một kích hoạt dữ liệu (với một mô hình xem) vào nút để cho phép một con trỏ chờ đợi.

<Button x:Name="NextButton" 
     Content="Go" 
     Command="{Binding GoCommand }"> 
    <Button.Style> 
     <Style TargetType="{x:Type Button}"> 
      <Setter Property="Cursor" Value="Arrow"/> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Path=IsWorking}" Value="True"> 
        <Setter Property="Cursor" Value="Wait"/> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Button.Style> 
</Button> 

Đây là mã từ quan điểm mô hình:

public class MainViewModel : ViewModelBase 
{ 
    // most code removed for this example 

    public MainViewModel() 
    { 
     GoCommand = new DelegateCommand<object>(OnGoCommand, CanGoCommand); 
    } 

    // flag used by data binding trigger 
    private bool _isWorking = false; 
    public bool IsWorking 
    { 
     get { return _isWorking; } 
     set 
     { 
     _isWorking = value; 
     OnPropertyChanged("IsWorking"); 
     } 
    } 

    // button click event gets processed here 
    public ICommand GoCommand { get; private set; } 
    private void OnGoCommand(object obj) 
    { 
     if (_selectedCustomer != null) 
     { 
     // wait cursor ON 
     IsWorking = true; 
     _ds = OrdersManager.LoadToDataSet(_selectedCustomer.ID); 
     OnPropertyChanged("GridData"); 

     // wait cursor off 
     IsWorking = false; 
     } 
    } 
} 
+5

Vui lòng thêm nhận xét cho phiếu bầu của bạn để giúp tôi hiểu lý do. Tôi đã sử dụng mã này nhiều lần với kết quả tốt. – Zamboni

+0

Mặc dù tôi nghĩ rằng đó không phải là giải pháp đơn giản nhất, tôi cũng không hiểu phiếu bầu số –

+4

Tôi cũng không nhận được phiếu giảm giá. Câu trả lời này rất hữu ích khi bạn đang sử dụng MVvM (vì vậy không có mã sau) và muốn điều khiển con trỏ cho một điều khiển cụ thể. Rất hữu dụng. –

4

Nếu ứng dụng của bạn sử dụng các công cụ async và bạn đang loay hoay với con trỏ chuột, bạn có thể muốn làm điều đó chỉ trong thread UI chính . Bạn có thể sử dụng chuỗi điều phối của ứng dụng cho rằng:

Application.Current.Dispatcher.Invoke(() => 
{ 
    // The check is required to prevent cursor flickering 
    if (Mouse.OverrideCursor != cursor) 
     Mouse.OverrideCursor = cursor; 
}); 
Các vấn đề liên quan