2011-03-07 40 views
7

Tôi đã đọc nhiều bài viết, bài viết vv về ràng buộc và mối quan hệ luồng của các điều khiển GUI. Có một số bài đăng mà mọi người không muốn sử dụng số Dispatcher.Tại sao tôi nên tránh sử dụng Dispatcher?

Tôi cũng có một người bạn làm việc tránh sử dụng Dispatcher trong mã của mình. Tôi hỏi anh ta vì lý do này nhưng câu trả lời của anh ấy không thỏa mãn tôi. Anh ta nói, anh ta không thích loại ma thuật như vậy ẩn trong lớp.

Vâng, tôi là người hâm mộ của lớp học sau.


public class BindingBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private Dispatcher Dispatcher 
    { 
#if SILVERLIGHT 
     get { return Deployment.Current.Dispatcher; } 
#else 
     get { return Application.Current.Dispatcher; } 
#endif 
    } 

    protected void RaisePropertyChanged<T>(Expression<Func<T>> expr) 
    { 
     var memberExpr = (MemberExpression)expr.Body; 
     string property = memberExpr.Member.Name; 

     var propertyChanged = PropertyChanged; 
     if (propertyChanged == null) return; 

     if (Dispatcher.CheckAccess()) 
     propertyChanged.Invoke(this, new PropertyChangedEventArgs(property)); 
     else 
     Dispatcher.BeginInvoke(() => RaisePropertyChanged(expr)); 
    } 
} 

Đây là câu hỏi. Có lý do nào khiến một số người không muốn sử dụng một lớp học như vậy không? Có lẽ tôi phải xem xét lại cách tiếp cận này.

Bạn phải thừa nhận, có một điều lạ. Dispatcher.CheckAccess() bị loại trừ khỏi Intellisense. Có lẽ họ là một chút đáng sợ do thực tế này.

Trân

EDIT:

Ok, một ví dụ khác. Hãy xem xét một đối tượng phức tạp. Bộ sưu tập làm ví dụ có lẽ không phải là ý tưởng hay nhất.


public class ExampleVm : BindingBase 
{ 
    private BigFatObject _someData; 
    public BigFatObject SomeData 
    { 
     get { return _someData; } 
     set 
     { 
     _someData = value; 
     RaisePropertyChanged(() => SomeData); 
     } 
    } 

    public ExampleVm() 
    { 
     new Action(LoadSomeData).BeginInvoke(null, null); //I know - it's quick and dirty 
    } 

    private void LoadSomeData() 
    { 
     // loading some data from somewhere ... 
     // result is of type BigFatObject 

     SomeData = result; // This would not work without the Dispatcher, would it? 
    } 
} 

Trả lời

5

Tôi cũng, cá nhân, không được chống lại Dispatcher trong các lớp mô hình chế độ xem. Tôi đã không thấy bất kỳ vấn đề quan trọng với nó, nhưng nó mang lại sự linh hoạt nhất cho mã của bạn.

Nhưng tôi thích ý tưởng đóng gói việc sử dụng Dispatcher trong mã cơ sở hạ tầng càng nhiều càng tốt. Cũng giống như bạn đã làm với phương pháp RaisePropertyChanged (BTW, trong trường hợp RaisePropertyChanged bạn không phải gửi bất cứ điều gì - ràng buộc đã làm điều đó cho bạn; bạn chỉ phải gửi thay đổi cho bộ sưu tập).

Điểm bất lợi lớn nhất và duy nhất mà tôi thấy ở đây là thử nghiệm đơn vị. Mọi thứ có thể trở nên phức tạp khi bạn thử kiểm tra logic của mình liên quan đến việc sử dụng Dispatcher. Hãy tưởng tượng nếu bạn có mã giống như thế này trong mô hình chế độ xem:

private void UpdateMyCollection() 
{ 
    IList<ModelData> dataItems = DataService.GetItems(); 

    // Update data on UI 
    Dispatcher.BeginInvoke(new Action(() => { 
     foreach (ModelData dataItem in dataItems) 
     { 
     MyObservableCollection.Add(new DataItemViewModel(dataItem)); 
     } 
    })); 
} 

Loại mã này khá điển hình khi cập nhật bộ sưu tập từ chuỗi không phải UI. Bây giờ, làm thế nào bạn sẽ viết một bài kiểm tra đơn vị kiểm tra logic của việc thêm các mục vào bộ sưu tập quan sát được? Trước hết, bạn cần phải giả lập thuộc tính DispatcherApplication.Currentnull trong khi thực hiện kiểm tra đơn vị. Thứ hai của tất cả, làm thế nào bạn sẽ thử nó? Bạn sẽ tạo một chuỗi đặc biệt bắt chước chuỗi giao diện người dùng và sử dụng Dispatcher của chuỗi đó? Vì vậy, loại điều này.

Điểm mấu chốt ở đây là nếu bạn muốn mã của bạn trở nên thân thiện với đơn vị, bạn cần nghĩ cách bạn sẽ giả lập số Dispatcher. Đây là mối quan tâm duy nhất.

Cập nhật:

Ví dụ thứ hai mà bạn cung cấp sẽ làm việc mà không Dispatcher (ràng buộc sẽ làm các trick).

+0

"(BTW, trong trường hợp RaisePropertyChanged bạn không phải gửi bất cứ điều gì - ràng buộc đã làm điều đó cho bạn; bạn chỉ phải gửi thay đổi cho bộ sưu tập)" Vâng, nếu điều này là đúng thì một cái gì đó đã được thay đổi kể từ. Net 3.5. Hãy xem xét một bộ sưu tập được tải trong một chủ đề tách biệt và sau đó chuyển qua chuỗi này đến một thuộc tính trong một ViewModel. Tôi không nghĩ điều đó có thể xảy ra nếu không có Dispatcher hoặc BackGroundWorker. – DHN

+0

Tôi không hiểu tại sao có nhược điểm trong khi kiểm tra đơn vị. Bạn có thể giải thích điều này một litte nhiều hơn, xin vui lòng? – DHN

+0

@DHN - Xem bản cập nhật của tôi để biết ví dụ về sự cố với các bài kiểm tra đơn vị. Đối với "Xem xét một bộ sưu tập được tải trong một chủ đề tách biệt và sau đó chuyển qua chuỗi này đến một thuộc tính trong một ViewModel" Tôi đã đề cập một cách rõ ràng rằng "bạn chỉ phải gửi các thay đổi tới các bộ sưu tập", vì vậy, vâng, bạn cần sử dụng ' Dispatcher' để sửa đổi các bộ sưu tập, nhưng không phải là các thuộc tính thông thường (nghĩa là bạn không phải tăng sự kiện 'INotifyPropertyChanged.PropertyChanged 'trên chuỗi giao diện người dùng, nhưng bạn phải tăng' INotifyCollectionChanged.CollectionChanged' trên chuỗi giao diện người dùng). –

Các vấn đề liên quan