【问题标题】:ProgressBar not updating on screen despite NotifyPropertyChanged working correctly尽管 NotifyPropertyChanged 工作正常,但 ProgressBar 未在屏幕上更新
【发布时间】:2012-04-03 05:57:00
【问题描述】:

首先,抱歉问题太长了。

我正在更新适用于 Windows Phone 7 的 Silverlight 应用程序,该应用程序当前将数据存储在多个 XML 文件中。我正在更新应用程序以使用 CompactSQL 数据库,并且在安装新版本后首次运行时,我必须将数据从 XML 文件迁移到数据库中。

我想要一个进度条 (IsIndeterminate=false) 向用户显示每个文件迁移到数据库的进度(因为该操作可能需要长达 2 分钟)。

问题在于,尽管 NotifyProperyChanged 事件触发并正确更新了进度条的值,但进度条并未更新(甚至显示)在屏幕上。当我在 XAML 中设置值时,它看起来很好(静态 - 但至少它是在屏幕上绘制的)。

我不知道为什么设备上根本没有显示进度条。

我的 INotifyChanged 设置

private int migrateCount;
public int MigrateCount //Prop used for ProgressBar.Value
{
    get
    {
        return this.migrateCount;
    }
    set
    {
        this.migrateCount = value;
        NotifyPropertyChanged("MigrateCount");
    }
}

public int MigrateTotal { get; set; } //Prop used for ProgressBar.Maximum

public void NotifyPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

void MainPage_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "MigrateCount")
    { 
        ProBar.Maximum = MigrateTotal; //ProBar is the name of my ProgressBar
        ProBar.Value = MigrateCount;
    }
}

public event PropertyChangedEventHandler PropertyChanged;

public MainPage()
{
    this.PropertyChanged += new PropertyChangedEventHandler(MainPage_PropertyChanged);
    ...
}

在 Loaded 而不是 OnNavigatedTo 中调用 MigrateDB 方法,因为操作系统会终止任何加载时间过长的应用。

    private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
    {
        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
        {
            string[] dirs = store.GetDirectoryNames();
            if (dirs.Length > 1) //Checks to see if there's any data to migrate 
            {
                MigrateDB();
                LoadData(); //Loads data from the DB once it's populated
            }
        }

此操作需要很长时间。每分钟大约 100 个 XML 文件,我希望用户拥有 30 到 300 个文件。

private void MigrateDB()
{
    string[] DirList;
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        DirList = store.GetDirectoryNames("*");
        MigrateTotal = DirList.Length - 1; // -1 to account for the "Shared" Dir
        foreach(...)
        {
           ... Does lots of IsoStore operations / XML serialising and DB updating
           MigrateCount++;
        }
    }
    ...
}        

【问题讨论】:

    标签: c# windows-phone-7 progress-bar ui-thread


    【解决方案1】:

    如果您将在另一个线程上工作,问题就解决了,因为进度条可以在用户界面上绘制他的进度。如果您在 MainThread 中工作,就像看起来一样,并且您的进度条正在等待任何空闲情况被允许绘制到用户界面,如果您有 CPU 消耗方法,这可能需要很长时间。

    解决方案的答案很简单;将您的数据库阅读器放入自己的线程中。 如果您使用以下软件,解决方案也很容易: ThreadStart() 将您的阅读器放入 Thread 中,Dispatcher.BeginInvoke() 在 GUI 上显示进度条值。 见http://msdn.microsoft.com/en-us/library/system.threading.threadstart.aspx

    http://www.devx.com/dotnet/Article/7003

    希望有帮助

    【讨论】:

    • 谢谢,我认为这可能与线程有关,但我不知道它是如何工作的。我最终用 BackgroundWorker 类修复了它,但如果没有你的帮助,我不会找到它。 :)
    【解决方案2】:

    我得到了一切工作。正如其他人所提到的,UI 线程被阻塞,我需要将 CPU 密集型代码转移到另一个线程。这释放了 UI(主)线程来更新进度条。我通过进行以下更改来做到这一点

    • 删除所有 INotifyPropertyChanged 代码。

    • 按照此 MSDN 教程 link 实现 BackgroundWorker 类。

    • 我将 MigrateDB 方法代码包装在 BackgroundWorker.DoWork 事件中,并且

    • 在 BackgroundWorker.ProgressChanged 事件中更新了我的 ProgressBar.Value。

    这是我最后的修改代码:

    public partial class MainPage : PhoneApplicationPage
    
    private BackgroundWorker bw = new BackgroundWorker();
    
    ...
    
    public MainPage()
        {
           ...
    
            bw.WorkerReportsProgress = true;
            bw.WorkerSupportsCancellation = false;
            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
            bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
            ...
        }
    
    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            LoadData(); //LINQ2SQL queries to display DB
        }
    
        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ProBar.Value = e.ProgressPercentage;
        }
    
    void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            double total = 0;
            double count = 0;
            BackgroundWorker worker = sender as BackgroundWorker;
            ... 
            foreach(...)
            {
               ... Does lots of IsoStore operations / XML serialising / DB updating
               count++;
               double cntr = count / total * 100;
               worker.ReportProgress((int)cntr);
            }
        }
    
    private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
             ...
             bw.RunWorkerAsync();
             ...
         }
    

    【讨论】:

      【解决方案3】:

      我认为有一个线程问题。如果您在主进程中更新进度条,则无法更新它。当 alwais 完成时,它可能会在函数结束时更新。 我不知道win手机中是否存在,但尝试使用后台工作人员

      【讨论】:

        猜你喜欢
        • 2013-11-12
        • 1970-01-01
        • 1970-01-01
        • 2019-01-14
        • 2016-03-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多