ProgressBar не обновляется на экране, несмотря на то, что NotifyPropertyChanged работает правильно - PullRequest
0 голосов
/ 03 апреля 2012

Прежде всего, извините за длину вопроса.

Я обновляю приложение Silverlight для 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);
    ...
}

Вызов метода MigrateDB в Loaded, а не в OnNavigatedTo, поскольку ОС завершает работу любого приложения, загрузка которого занимает слишком много времени.

    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 ]

2 голосов
/ 03 апреля 2012

Проблема решается, если вы будете работать в другом потоке, так как индикатор прогресса может отображать свой прогресс в интерфейсе пользователя.Если вы работаете в MainThread так, как он выглядит, и ваш индикатор прогресса ожидает, чтобы любая неактивная ситуация была разрешена для отрисовки пользовательского интерфейса, это может занять много времени, если у вас есть методы, потребляющие ЦП.

Multithreading

Ответ решения прост;перенесите вашу базу данных читателя в свой собственный поток.Решение в виде программного обеспечения также может быть простым, если вы используете: ThreadStart(), чтобы поместить читателя в Thread, и Dispatcher.BeginInvoke(), чтобы отображать значения индикатора выполнения в графическом интерфейсе.См. http://msdn.microsoft.com/en-us/library/system.threading.threadstart.aspx

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

Надеюсь, что поможет

2 голосов
/ 03 апреля 2012

У меня все работает. Как уже упоминалось, поток пользовательского интерфейса блокировался, и мне нужно было перенести интенсивный процессорный код в другой поток. Это освободило основной поток пользовательского интерфейса для обновления индикатора выполнения. Я сделал это, внеся следующие изменения

  • Удаление всего кода INotifyPropertyChanged.

  • Реализация класса BackgroundWorker с помощью этого учебного руководства MSDN ссылка .

  • Я обернул код метода MigrateDB внутри события BackgroundWorker.DoWork и

  • Обновлено мое значение ProgressBar.Value в событии BackgroundWorker.ProgressChanged.

Это мой последний рабочий код с изменениями:

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();
         ...
     }
0 голосов
/ 03 апреля 2012

Я думаю, что есть серьезная проблема.Если вы обновите индикатор выполнения в основном процессе, его невозможно обновить.Может быть, он обновится в конце функции, когда завершится alwais.Я не знаю, существует ли в win phone, но попробуйте использовать фоновый рабочий

...