从后台线程更新进度条

时间:2013-02-11 09:04:41

标签: c# wpf progress-bar

我有一个进度条,其值绑定到属性:

                <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>

和财产:

       public double CompassLogLoadPercent {
        get { return _compassLogLoadPercent; }
        private set {
            if (value != _compassLogLoadPercent) {
                _compassLogLoadPercent = value;
                NotifyPropertyChanged();
            }
        }
    }

并在单独的线程中更新其值:

   for (int j = 0; j < lines.Count(); j++) {
      ...
      CompassLogLoadPercent = ((double) j /lines.Count())*100;
   }

并使用TASK创建线程:

Task.Run(() => { LoadLogFile(fileName); });

为什么进度条没有更新,我应该如何解决?

更新更多信息

Datacontext :(我确定dataContext是正确的)

cLT.progressBar.DataContext = logSession;

以及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));
        }
    }

1 个答案:

答案 0 :(得分:4)

问题在于你没有向我们展示过的东西。基本技术是健全的。 (特别是,在工作线程上引发PropertyChanged事件通知没有错,因为WPF的数据绑定系统检测到何时发生,并自动安排更新UI线程上的目标UI元素。)

这是一个完整的例子。这是你的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>

这是你的代码隐藏:

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));
            }
        }
    }
}

这说明了您尝试使用的技术的工作版本。

所以你的工作不起作用的事实必定是由于你没有向我们展示的东西。一些可能的解释:

  • 您的UI线程可能被阻止。如果UI线程忙,则不会处理数据绑定更新。 (当数据绑定检测到工作线程上的数据源发生更改时,它会将消息发布到相关的调度程序线程,如果调度程序线程忙,则不会处理该消息。)
  • 数据来源可能不在您DataContext的{​​{1}}中 - 您没有向我们展示您设置上下文的位置,因此可能出错。
  • 引发ProgressBar事件(您的PropertyChanged代码)的代码可能是错误的 - 您没有显示该代码,并且不清楚它是如何知道在提升时使用的属性名称事件

要检查第一个,只需在此后台工作正在进行时查看您的UI是否响应用户输入。如果不是,那就是为什么更新没有通过。

2月25日更新,以添加相关链接

在考虑如何处理这种情况时我还能说些什么,我得出的结论是它太大了,无法适应单个StackOverflow的答案。所以我在一个需要将信息加载到UI的后台线程上进行非平凡处理时写了一系列关于性能考虑因素的博客文章:http://www.interact-sw.co.uk/iangblog/2013/02/14/wpf-async-too-fast