2010-09-18 33 views
10

Trong WPF do sự phức tạp về cách giao diện được cập nhật, đôi khi tôi phải thực hiện các hành động sau một thời gian trễ ngắn.Gửi văn bản bị trì hoãn?

Hiện nay tôi đang làm điều này chỉ đơn giản bằng cách: (?)

 var dt = new DispatcherTimer(DispatcherPriority.Send); 
     dt.Tick += (s, e) => 
     { 
      dt.Stop(); 
      //DoStuff 
     }; 
     dt.Interval = TimeSpan.FromMilliseconds(200); 
     dt.Start(); 

Nhưng đó là cả một chút xấu xí và có lẽ quá nhiều chi phí để tạo ra một bộ đếm thời gian mới mỗi lần gì tốt nhất từ ​​một quan điểm hiệu suất để làm điều đó, tức là thực hiện nhanh nhất? Và cách tốt để viết lại đoạn code trên vào một cái gì đó như là những gì:

 this.Dispatcher.BeginInvoke(new Action(delegate() 
     { 
      //DoStuff 
     }), DispatcherPriority.Send,TimeSpan.FromMilliseconds(200)); 

đâu Khoảng thời gian là sự chậm trễ, Cảm ơn bạn cho bất kỳ đầu vào :)

+0

Thay vì chờ đợi cho một cái gì đó trước khi cập nhật, bạn không thể di chuyển trách nhiệm để cập nhật giao diện người dùng cho nội dung bạn đang đợi? Điều này sẽ tránh hẹn giờ. – x0n

+0

không may là không, đó là những thứ giống như cập nhật ui và ẩn nó sau một khoảng thời gian ngắn nên cửa sổ được cập nhật khi nó được hiển thị trở lại – Homde

Trả lời

11

tôi sẽ không giả rằng DispatcherTimer là nặng-weight ... tại sao không chỉ viết một phương pháp mở rộng trên Dispatcher cho phép bạn sử dụng cú pháp bạn muốn, và sử dụng DispatcherTimer ở chế độ nền? Cá nhân tôi sẽ gọi nó là DelayInvoke hơn BeginInvoke dù ... và tôi cũng muốn sửa chữa nó luôn luôn sử dụng Action chứ không phải là một đại biểu tùy tiện ... mà sẽ làm cho nó dễ dàng hơn để sử dụng biểu thức lambda:

Dispatcher.DelayInvoke(TimeSpan.FromMilliseconds(200),() => { ... 
}); 

(Tôi có xu hướng tìm thấy nó dễ đọc hơn nếu các hàm ẩn danh được sử dụng làm đối số cuối cùng trong một cuộc gọi phương thức, nhưng đó chỉ là một sở thích cá nhân.)

Cho rằng bạn sẽ có thể muốn sử dụng mili giây hầu hết thời gian, bạn cũng có thể có một phương thức trợ giúp khác:

Dispatcher.DelayInvokeMillis(200,() => { ... 
}); 

Một giải pháp thay thế khác để thử chỉ đơn thuần là sử dụng phương thức BeginInvoke hiện có nhưng với mức ưu tiên rất thấp, vì vậy ủy nhiệm của bạn sẽ chỉ được gọi sau khi mọi thứ khác đã hoàn thành. Nếu không biết chi tiết về tình huống của bạn, thật khó để biết liệu nó có hiệu quả hay không - nhưng đáng để thử.

+0

Một phương pháp mở rộng sẽ rất đẹp, nhưng điều đó không có nghĩa là trước tiên tôi phải bắt đầu trên dispatcher để được vào đúng chủ đề và sau đó thiết lập bộ đếm thời gian, đó là một chi phí ít hơn nhiều so với chỉ có bộ đếm thời gian? Có thể không phải là một vấn đề mặc dù ... – Homde

+0

@MattiasK: Tại sao nó cần phải làm điều đó? Nó sẽ không * thực sự * cần phải tương tác với các điều phối viên ở tất cả ... đó sẽ chỉ là cho cảm giác nhất quán. Phải thừa nhận rằng tôi không biết điều gì sẽ xảy ra nếu bạn tạo một DispatcherTimer từ một luồng khác ... nhưng nếu nó hoạt động khi được thực hiện trực tiếp, nó sẽ làm việc từ một phương thức mở rộng mà không có thêm bất kỳ vấn đề nào. –

+2

@MattiasK: Tôi vừa kiểm tra, và bạn có thể nói cho constructor DispatcherTimer mà Dispatcher nó nên chạy - vì vậy bạn sẽ sử dụng quá tải đó từ phương thức mở rộng và chỉ định Dispatcher đã được truyền cho phương thức. –

0

Bạn có thể sử dụng lớp DelayBinding của Paul Stowell từ đây: http://www.paulstovell.com/wpf-delaybinding.

Với điều này có thể liên kết với DependencyProperty trên một lớp có thể thực hiện tác vụ khi thuộc tính thay đổi. Việc ràng buộc sẽ quản lý sự chậm trễ. Có thể đặc biệt tốt đẹp nếu bạn có thiết kế kiểu MVVM.

3

Một cách .NET 4.5:

public async void MyMethod() 
    { 
     await Task.Delay(20); 
     await Dispatcher.BeginInvoke((Action)DoStuff); 
    } 
0

Tôi không ngây thơ của các DispatcherTimer vì không có cách nào dễ dàng để vượt qua các thông số trong khác hơn là thông qua chức năng phạm vi/đóng cửa.

Thay vào đó tôi sử dụng một Task.Delay() và quấn đó vào một phương pháp Dispatcher.Delay() phần mở rộng:

public static class DispatcherExtensions 
{ 

    public static void Delay(this Dispatcher disp, int delayMs, 
          Action<object> action, object parm = null) 
    { 
     var ignore = Task.Delay(delayMs).ContinueWith((t) => 
     { 
      disp.Invoke(action, parm); 
     }); 
    } 

    public static void DelayWithPriority(this Dispatcher disp, int delayMs, 
         Action<object> action, object parm = null, 
         DispatcherPriority priority = DispatcherPriority.ApplicationIdle) 
    { 
     var ignore = Task.Delay(delayMs).ContinueWith((t) => 
     { 
      disp.BeginInvoke(action, priority, parm); 
     }); 

    } 

    public static async Task DelayAsync(this Dispatcher disp, int delayMs, 
         Action<object> action, object parm = null, 
         DispatcherPriority priority = DispatcherPriority.ApplicationIdle) 
    { 
     await Task.Delay(delayMs); 
     await disp.BeginInvoke(action, priority, parm); 
    } 
} 

Để gọi này sau đó:

Dispatcher.Delay(4000, (win) => 
{ 
    var window = win as MainWindow; 
    window.ShowStatus(null, 0); 
},this); 
Các vấn đề liên quan