0

首先,抱歉问题的长度。

我正在更新一个 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++;
        }
    }
    ...
}        
4

3 回答 3

2

如果您将在另一个线程上工作,问题就解决了,因为进度条被允许在用户界面上绘制他的进度。如果您在 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

希望有帮助

于 2012-04-03T06:06:12.733 回答
2

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

  • 删除所有 INotifyPropertyChanged 代码。

  • 按照这个 MSDN 教程链接实现 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();
         ...
     }
于 2012-04-03T14:24:04.443 回答
0

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

于 2012-04-03T06:04:06.947 回答