2011-10-23 8 views
6

Tôi có một ứng dụng được viết bằng wpf, tải một số trang web, phân tích mã html và lưu một số giá trị.Phải tạo DependencySource trên cùng một Thread với DependencyObject

class ListOfItems 
{  
    public List<SomeObject> ListToBind; 
    public void DownloadItems() 
    { 
     Task.Factory.StartNew(() => 
     { 
      ... 
      ... 
      if (OnDownloadCompleted != null) 
       OnDownloadCompleted(this, EventArgs.Empty); 
     } 
    } 
} 

class SomeObject 
{ 
    public string NameOfItem; 
    public MyClass Properties; 
} 

class MyClass 
{ 
    public int Percentage; 
    public SolidColorBrush Color; 
} 

Đây là mô hình đối tượng tôi đang sử dụng. Đó là phiên bản đơn giản và tôi không muốn bạn tổ chức lại nó, có một lý do tôi đã viết nó theo cách này. Trong lớp ListOfItems là phương thức thực hiện tất cả công việc (có một số phương pháp khác được sử dụng bên trong để tạo mã có thể đọc được) - tải xuống nguồn, phân tích cú pháp và điền ListToBind với dữ liệu, f.e.

[0] => NameOfItem = "FirstOne", Properties = {99, #FF00FF00} 
[1] => NameOfItem = "SecondOne", Properties = {50, #FFFF0000} 
etc. 

Như bạn có thể thấy, khi phương pháp này DownloadItems hoàn thành công việc của mình, OnDownloadCompleted Sự kiện này được nâng lên. Trong các chủ đề chính được mã sau

void listOfItems_OnDownloadCompleted(object sender, EventArgs args) 
{ 
    dataGrid.Dispatcher.Invoke(new Action(() => { 
       dataGrid.ItemsSource = ListOfItemsInstance.ListToBind; 
      })); 
} 

DataGrid trên MainWindow.xaml được làm đầy với các giá trị, vì sau đoạn mã XAML.

<DataGrid Name="dataGrid" AutoGenerateColumns="False"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Tag" Binding="{Binding Name}"/> 
     <DataGridTextColumn Header="Color" Binding="{Binding MyClass.Percentage}"> 
      <!--<DataGridTextColumn.CellStyle> 
       <Style TargetType="DataGridCell"> 
        <Setter Property="Background" Value="{Binding MyClass.Color}" /> 
       </Style> 
      </DataGridTextColumn.CellStyle>--> 
     </DataGridTextColumn> 
    </DataGrid.Columns> 
</DataGrid> 

Nó hoạt động tốt. Nhưng có vấn đề này. Cố gắng bỏ ghi chú đoạn trích xaml đã nhận xét và bạn sẽ gặp lỗi Must create DependencySource on same Thread as the DependencyObject..

Cuối cùng, câu hỏi của tôi là, cách tránh lỗi này?

EDIT:

Nó sẽ giống như thế này cuối cùng. Bức ảnh này được lấy từ MS Excel và được tô màu trong Adobe Photoshop.

example

Trả lời

22

SolidColorBrushFreezable là một DispatcherObject có nguồn gốc. DispatcherObjects có ái lực luồng - tức là nó chỉ có thể được sử dụng/tương tác với trên chuỗi mà nó được tạo ra. Freezables tuy nhiên cung cấp khả năng đóng băng một thể hiện. Điều này sẽ ngăn chặn bất kỳ thay đổi nào khác cho đối tượng nhưng nó cũng sẽ giải phóng mối quan hệ luồng. Vì vậy, bạn có thể thay đổi nó để tài sản của bạn không lưu trữ DependencyObject như SolidColorBrush và thay vào đó chỉ cần lưu trữ màu. Hoặc bạn có thể đóng băng SolidColorBrush mà bạn đang tạo bằng cách sử dụng phương thức Freeze.

+0

Cảm ơn bạn đã giải thích này. Câu trả lời thứ hai trong câu hỏi này có lẽ là theo cùng một cách, nhưng vấn đề là tôi không biết, những gì để Freeze. Bây giờ, khi bạn nói với tôi SolidColorBrush có nguồn gốc từ DispatcherObject và giải thích tình hình, tôi đã làm cho nó hoạt động. Cảm ơn bạn một lần nữa, tiền thưởng là của bạn. –

1

Tôi nghĩ rằng cách tiêu chuẩn là để lấy được các đối tượng dữ liệu từ FreezableFreeze nó trước khi đi qua nó để thread khác. Khi đối tượng bị đóng băng, bạn không thể thay đổi nó nữa, do đó không có nguy cơ phát tán lỗi.

Tùy chọn khác có thể là làm cho đối tượng dữ liệu trở thành đối tượng C# đơn giản (không bắt nguồn từ số DispatcherObject) và tự thực hiện INotifyPropertyChanged.

+0

Thuộc tínhThay đổi sự kiện không nhất thiết phải diễn ra trên chuỗi ui, vì chúng được [tự động so khớp với chuỗi giao diện người dùng. [http://stackoverflow.com/a/11015784] – user1912383

+0

@ user1912383: Bạn nói đúng, tất nhiên. Nhưng tôi không biết rằng 5 năm trước ... – Niki