Reputation: 1225
I have a progressbar and its value is binded to a property:
<ProgressBar x:Name="progressBar"
Margin="0,2,0,0"
Height="20"
Value="{Binding CompassLogLoadPercent}"
Foreground="Blue"
Visibility="{Binding CompassLogLoadCompleted,
Converter={StaticResource BooleanToVisibilityConverter}}"
ToolTip="Loading">
</ProgressBar>
and the property:
public double CompassLogLoadPercent {
get { return _compassLogLoadPercent; }
private set {
if (value != _compassLogLoadPercent) {
_compassLogLoadPercent = value;
NotifyPropertyChanged();
}
}
}
and in a seperate thread its value is updated:
for (int j = 0; j < lines.Count(); j++) {
...
CompassLogLoadPercent = ((double) j /lines.Count())*100;
}
and the thread is created using TASK:
Task.Run(() => { LoadLogFile(fileName); });
Why is progressbar not updating and how should I fix this?
UPDATE: More Info
Datacontext: (Im sure that the dataContext is Correct)
cLT.progressBar.DataContext = logSession;
and implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(
[CallerMemberName] String propertyName = "") {
PropertyChangedEventHandler eventHandler = PropertyChanged;
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Upvotes: 1
Views: 2100
Reputation: 14567
The problem lies somewhere in something you haven't shown us. The basic technique is sound. (In particular, there's nothing wrong with raising PropertyChanged
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.)
Here's a complete example that does work. Here's your XAML:
<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">
<Grid>
<ProgressBar
x:Name="progressBar"
VerticalAlignment="Top" Height="20"
Value="{Binding CompassLogLoadPercent}">
</ProgressBar>
<Button Content="Button" HorizontalAlignment="Left" Margin="10,25,0,0" VerticalAlignment="Top"
Width="75" RenderTransformOrigin="-1.24,-0.045" Click="Button_Click_1"/>
</Grid>
</Window>
and here's your codebehind:
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(() =>
{
for (int i = 0; i < 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));
}
}
}
}
This illustrates a working version of the technique you're trying to use.
So the fact that yours doesn't work must be due to something you've not shown us. Some possible explanations:
DataContext
for your ProgressBar
- you've not shown us where you set the context, so that could well be wrong.PropertyChanged
event (your NotifyPropertyChanged
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.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.
Updated 25th February to add relevant link
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: http://www.interact-sw.co.uk/iangblog/2013/02/14/wpf-async-too-fast
Upvotes: 4