简体   繁体   English

从后台线程更新进度条

[英]Updating progressbar from a background thread

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创建线程:

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) Datacontext :(我确定dataContext是正确的)

cLT.progressBar.DataContext = logSession;

and implementation of INotifyPropertyChanged 和实现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));
        }
    }

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.) (特别是,在工作线程上引发PropertyChanged事件通知没有任何问题,因为WPF的数据绑定系统检测到何时发生,并自动安排更新UI线程上的目标UI元素。)

Here's a complete example that does work. 这是一个完整的例子。 Here's your XAML: 这是你的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: 一些可能的解释:

  • Your UI thread might be blocked. 您的UI线程可能被阻止。 If the UI threads is busy, the data binding updates will not be processed. 如果UI线程忙,则不会处理数据绑定更新。 (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.) (当数据绑定检测到工作线程上的数据源发生更改时,它会将消息发布到相关的调度程序线程,如果调度程序线程忙,则不会处理该消息。)
  • The data source might not be in the DataContext for your ProgressBar - you've not shown us where you set the context, so that could well be wrong. 数据源可能不在ProgressBarDataContext中 - 您没有向我们展示您设置上下文的位置,因此这可能是错误的。
  • The code that raises the 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. 引发PropertyChanged事件的代码(您的NotifyPropertyChanged代码)可能是错误的 - 您没有显示该代码,并且不清楚它如何知道在引发事件时要使用的属性名称。

To check for the first one, just see if your UI is responsive to user input while this background work is in progress. 要检查第一个,只需在此后台工作正在进行时查看您的UI是否响应用户输入。 If it's not, then that's why the updates aren't getting through. 如果不是,那就是为什么更新没有通过。

Updated 25th February to add relevant link 2月25日更新,添加相关链接

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM