Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The problem lies somewhere in something you haven't shown us. The basic technique is sound. (In particular, there's nothing wrong with raising <code>PropertyChanged</code> event notifications on a worker thread, because WPF's data binding system detects when that happens, and automatically arranges to update the target UI element on the UI thread.)</p> <p>Here's a complete example that does work. Here's your XAML:</p> <pre><code>&lt;Window x:Class="BackgroundThreadUpdate.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"&gt; &lt;Grid&gt; &lt;ProgressBar x:Name="progressBar" VerticalAlignment="Top" Height="20" Value="{Binding CompassLogLoadPercent}"&gt; &lt;/ProgressBar&gt; &lt;Button Content="Button" HorizontalAlignment="Left" Margin="10,25,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="-1.24,-0.045" Click="Button_Click_1"/&gt; &lt;/Grid&gt; &lt;/Window&gt; </code></pre> <p>and here's your codebehind:</p> <pre><code>using System.ComponentModel; using System.Threading; using System.Threading.Tasks; using System.Windows; namespace BackgroundThreadUpdate { public partial class MainWindow : Window { private MySource _src; public MainWindow() { InitializeComponent(); _src = new MySource(); DataContext = _src; } private void Button_Click_1(object sender, RoutedEventArgs e) { Task.Run(() =&gt; { for (int i = 0; i &lt; 100; ++i) { Thread.Sleep(100); _src.CompassLogLoadPercent = i; } }); } } public class MySource : INotifyPropertyChanged { private double _compassLogLoadPercent; public double CompassLogLoadPercent { get { return _compassLogLoadPercent; } set { if (_compassLogLoadPercent != value) { _compassLogLoadPercent = value; OnPropertyChanged("CompassLogLoadPercent"); } } } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } } </code></pre> <p>This illustrates a working version of the technique you're trying to use.</p> <p>So the fact that yours doesn't work must be due to something you've not shown us. Some possible explanations:</p> <ul> <li>Your UI thread might be blocked. If the UI threads is busy, the data binding updates will not be processed. (When data binding detects a change from a data source on a worker thread, it posts a message to the relevant dispatcher thread, and that message won't be processed if the dispatcher thread is busy.)</li> <li>The data source might not be in the <code>DataContext</code> for your <code>ProgressBar</code> - you've not shown us where you set the context, so that could well be wrong.</li> <li>The code that raises the <code>PropertyChanged</code> event (your <code>NotifyPropertyChanged</code> code) might be wrong - you've not shown that code, and it's not clear how it knows what property name to use when raising the event.</li> </ul> <p>To check for the first one, just see if your UI is responsive to user input while this background work is in progress. If it's not, then that's why the updates aren't getting through.</p> <p><strong>Updated 25th February to add relevant link</strong></p> <p>In thinking about what else I could say about how to handle this scenario, I came to the conclusion that it was too big to fit into a single StackOverflow answer. so I wrote a series of blog posts about performance considerations when doing non-trivial processing on a background thread that needs to load information into a UI: <a href="http://www.interact-sw.co.uk/iangblog/2013/02/14/wpf-async-too-fast" rel="nofollow">http://www.interact-sw.co.uk/iangblog/2013/02/14/wpf-async-too-fast</a></p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload