2008-09-05 96 views
6

我有一個圖像控件,它的源綁定到一個對象上的屬性(字符串url到圖像)。進行服務調用後,我使用新的URL更新數據對象。它在調用PropertyChanged事件後離開我的代碼後拋出異常。Silverlight DataBinding跨線程問題

數據結構和服務邏輯都是在不知道UI的核心dll中完成的。當我無法訪問分派器時,如何與UI線程同步? PS:訪問Application.Current.RootVisual以獲得Dispatcher不是一個解決方案,因爲根目錄位於不同的線程上(導致我需要防止的確切異常)。

PPS:這只是一個圖像控制的問題,綁定到任何其他UI元素,交叉線程問題是爲您處理的。

回答

0

Application類上RootVisual的屬性獲取方有一個導致該異常的線程檢查。我周圍這讓在我自己的財產存放根視覺的調度員在我App.xaml.cs:

public static Dispatcher RootVisualDispatcher { get; set; } 

private void Application_Startup(object sender, StartupEventArgs e) 
{ 
    this.RootVisual = new Page(); 
    RootVisualDispatcher = RootVisual.Dispatcher; 
} 

如果再調用BeginInvoke上App.RootVisualDispatcher而非Application.Current.RootVisual.Dispatcher你不該」噸得到這個例外。

0

我遇到類似的問題,這一點,但是這是在Windows窗體:

我已經有它自己的線程,更新關於另一個進程統計類,那裏是我的UI控件是數據綁定到這個對象。我也陷入了跨線程調用的問題,這是我如何解決它:

Form m_MainWindow; //Reference to the main window of my application 
protected virtual void OnPropertyChanged(string propertyName) 
{ 
    if(PropertyChanged != null) 
    if(m_MainWindow.InvokeRequired) 
     m_MainWindow.Invoke(
     PropertyChanged, this, new PropertyChangedEventArgs(propertyName); 
    else 
     PropertyChanged(this, new PropertyChangedEventArgs(propertyName); 
} 

這似乎工作的偉大,如果任何人有意見,請讓我知道。

7
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => {...}); 

也期待here.

0

當過我們要更新UI相關的項目採取行動,應在UI線程發生否則你會得到一個無效的橫紗訪問異常

Deployment.Current.Dispatcher.BeginInvoke(() => 

{ 

UpdateUI(); // DO the actions in the function Update UI 

}); 

public void UpdateUI() 

{ 

//to do :Update UI elements here 

} 
0

INotifyPropertyChanged接口用於通知客戶端(通常是綁定客戶端)屬性值已更改。

例如,考慮具有名爲FirstName的屬性的Person對象。爲了提供通用屬性更改通知,Person類型實現INotifyPropertyChanged接口,並在更改FirstName時引發PropertyChanged事件。

對於在綁定的客戶端和一個數據源之間的結合發生變化通知,您的bound類型要麼:

貫徹INotifyPropertyChanged接口(優選的)。

爲綁定類型的每個屬性提供更改事件。

不要這樣做。

實施例:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Drawing; 
using System.Runtime.CompilerServices; 
using System.Windows.Forms; 

// Change the namespace to the project name. 
namespace TestNotifyPropertyChangedCS 
{ 
    // This form demonstrates using a BindingSource to bind 
    // a list to a DataGridView control. The list does not 
    // raise change notifications. However the DemoCustomer type 
    // in the list does. 
    public partial class Form1 : Form 
    { 
     // This button causes the value of a list element to be changed. 
     private Button changeItemBtn = new Button(); 

     // This DataGridView control displays the contents of the list. 
     private DataGridView customersDataGridView = new DataGridView(); 

     // This BindingSource binds the list to the DataGridView control. 
     private BindingSource customersBindingSource = new BindingSource(); 

     public Form1() 
     { 
      InitializeComponent(); 

      // Set up the "Change Item" button. 
      this.changeItemBtn.Text = "Change Item"; 
      this.changeItemBtn.Dock = DockStyle.Bottom; 
      this.changeItemBtn.Click += 
       new EventHandler(changeItemBtn_Click); 
      this.Controls.Add(this.changeItemBtn); 

      // Set up the DataGridView. 
      customersDataGridView.Dock = DockStyle.Top; 
      this.Controls.Add(customersDataGridView); 

      this.Size = new Size(400, 200); 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      // Create and populate the list of DemoCustomer objects 
      // which will supply data to the DataGridView. 
      BindingList<DemoCustomer> customerList = new BindingList<DemoCustomer>(); 
      customerList.Add(DemoCustomer.CreateNewCustomer()); 
      customerList.Add(DemoCustomer.CreateNewCustomer()); 
      customerList.Add(DemoCustomer.CreateNewCustomer()); 

      // Bind the list to the BindingSource. 
      this.customersBindingSource.DataSource = customerList; 

      // Attach the BindingSource to the DataGridView. 
      this.customersDataGridView.DataSource = 
       this.customersBindingSource; 

     } 

     // Change the value of the CompanyName property for the first 
     // item in the list when the "Change Item" button is clicked. 
     void changeItemBtn_Click(object sender, EventArgs e) 
     { 
      // Get a reference to the list from the BindingSource. 
      BindingList<DemoCustomer> customerList = 
       this.customersBindingSource.DataSource as BindingList<DemoCustomer>; 

      // Change the value of the CompanyName property for the 
      // first item in the list. 
      customerList[0].CustomerName = "Tailspin Toys"; 
      customerList[0].PhoneNumber = "(708)555-0150"; 
     } 

    } 

    // This is a simple customer class that 
    // implements the IPropertyChange interface. 
    public class DemoCustomer : INotifyPropertyChanged 
    { 
     // These fields hold the values for the public properties. 
     private Guid idValue = Guid.NewGuid(); 
     private string customerNameValue = String.Empty; 
     private string phoneNumberValue = String.Empty; 

     public event PropertyChangedEventHandler PropertyChanged; 

     // This method is called by the Set accessor of each property. 
     // The CallerMemberName attribute that is applied to the optional propertyName 
     // parameter causes the property name of the caller to be substituted as an argument. 
     private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     // The constructor is private to enforce the factory pattern. 
     private DemoCustomer() 
     { 
      customerNameValue = "Customer"; 
      phoneNumberValue = "(312)555-0100"; 
     } 

     // This is the public factory method. 
     public static DemoCustomer CreateNewCustomer() 
     { 
      return new DemoCustomer(); 
     } 

     // This property represents an ID, suitable 
     // for use as a primary key in a database. 
     public Guid ID 
     { 
      get 
      { 
       return this.idValue; 
      } 
     } 

     public string CustomerName 
     { 
      get 
      { 
       return this.customerNameValue; 
      } 

      set 
      { 
       if (value != this.customerNameValue) 
       { 
        this.customerNameValue = value; 
        NotifyPropertyChanged(); 
       } 
      } 
     } 

     public string PhoneNumber 
     { 
      get 
      { 
       return this.phoneNumberValue; 
      } 

      set 
      { 
       if (value != this.phoneNumberValue) 
       { 
        this.phoneNumberValue = value; 
        NotifyPropertyChanged(); 
       } 
      } 
     } 
    } 
}