Unlike the Highlander there can be more than one Dispatcher. Just because you invokeSystem.Windows.Threading.Dispatcher.CurrentDispatcher does not mean you will always get the Dispatcher responsible for executing tasks on the logical tree.
Consider this example:
<Window x:Class="WpfDispatcherInfalibility.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="75" Title="MainWindow" Width="100"> <Grid> <TextBlock Text="{Binding Path=Field1}" /> </Grid> </Window>
namespace WpfDispatcherInfalibility { using System; using System.ComponentModel; using System.Threading; using System.Windows.Threading; /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : INotifyPropertyChanged { private string field1 = "Default"; public MainWindow() { InitializeComponent(); this.DataContext = this; var thread = new Thread(this.WorkerMethod) { Name = "My worker thread 1" }; thread.Start(); } public event PropertyChangedEventHandler PropertyChanged; public string Field1 { get { return this.field1; } set { this.field1 = value; this.RaisePropertyChanged("Field1"); } } private void RaisePropertyChanged(string name) { var handler = this.PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } private void WorkerMethod() { // This will not retrieve the UI dispatcher because it is simply getting a dispatcher associated // with this thread and this is not the UI thread. Just because you invoke Dispatcher.CurrentDispatcher // does not mean you will be given the dispatcher associated with the UI. var dispatcher = Dispatcher.CurrentDispatcher; string threadName = Thread.CurrentThread.Name; // The lambda will never be invoked because the dispatcher retrieved is not running. dispatcher.BeginInvoke(new Action(() => this.Field1 = "Field set from thread " + threadName)); } } }
As expected the UI shows the following window. And this window's text does not change.
What is the moral of the story?
Keep a reference to the dispatcher from a known point inside the controller for your xaml. Or you can get it from any derivative of DispatcherObject (which is the root object of all Xaml components).
No comments:
Post a Comment