尽管NotifyPropertyChanged正常工作,ProgressBar仍未在屏幕上更新

时间:2012-04-03 05:57:01

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

首先,对不起问题的长度。

我正在更新Silverlight for Windows Phone 7应用程序,该应用程序当前将数据存储在多个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++;
        }
    }
    ...
}        

3 个答案:

答案 0 :(得分:2)

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

Multithreading

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

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

希望有所帮助

答案 1 :(得分: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();
         ...
     }

答案 2 :(得分:0)

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