2008-09-05 2 views
6

У меня есть элемент управления Image с его источником, привязанным к свойству объекта (строковый url для изображения). После вызова службы я обновляю объект данных с новым URL-адресом. Исключение выдается после того, как он покидает мой код, после вызова события PropertyChanged.Silverlight DataBinding проблема с перекрестными потоками

Структура данных и логика обслуживания выполняются в базе данных dll, которая не знает пользовательского интерфейса. Как мне синхронизировать с потоком пользовательского интерфейса, когда я не могу получить доступ к диспетчеру?

PS: Доступ к Application.Current.RootVisual для доступа к диспетчеру не является решением, потому что корневой визуал находится в другом потоке (в результате чего необходимо исключить точное исключение).

PPS: Это только проблема с управлением изображением, привязка к любому другому элементу ui, проблема с перекрестными потоками обрабатывается для вас.

ответ

0

Свойство getter для RootVisual в классе Application имеет проверку потока, которая вызывает это исключение. Я получил вокруг этого хранения диспетчера корня визуала в моей собственности в моем 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 вы не должны» t получить это исключение.

0

я столкнулся с подобным вопросом к этому, но это было в окне формы:

У меня есть класс, который имеет собственный поток, обновление статистики о другом процессе, есть контроль в моем 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 связанные элементы, действие должно происходить в потоке пользовательского интерфейса иначе вы получите исключение доступа недействителен кросс нить

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

{ 

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

}); 

public void UpdateUI() 

{ 

//to do :Update UI elements here 

} 
0

INotifyPropertyChanged интерфейс используется для уведомления клиентов, обычно связывающих клиентов, что значение свойства изменилось.

Например, рассмотрите объект Person с свойством FirstName. Чтобы предоставить уведомление об изменении общего свойства, тип Person реализует интерфейс INotifyPropertyChanged и вызывает событие PropertyChanged при изменении FirstName.

Для получения уведомления об изменении произойти в привязке между клиентом и связанного с источником данных, ваша оценка тип должен либо:

Реализовать 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(); 
       } 
      } 
     } 
    } 
}