首先,对不起问题的长度。
我正在更新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++;
}
}
...
}
答案 0 :(得分:2)
如果您将使用另一个线程,因为允许进度条在用户界面上绘制进度,问题就解决了。如果您在MainThread中工作似乎看起来像,并且您的进度条正在等待任何空闲情况被允许绘制到用户界面,如果您有CPU消耗的方法,则可能需要很长时间。
解决方案的答案很简单;将数据库读取器放入自己的线程中。
如果使用以下软件解决方案也很简单:
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手机中是否存在但是尝试使用后台工作者