0

初めまして、質問が長くなってしまい申し訳ありません。

現在複数の XML ファイルにデータを格納している Silverlight for Windows Phone 7 アプリを更新しています。CompactSQL DB を使用するようにアプリを更新しています。新しいバージョンをインストールした後、最初の実行時に XML ファイルから DB にデータを移行する必要があります。

各ファイルが DB に移行されるときの進行状況をユーザーに示す進行状況バー (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);
    ...
}

読み込みに時間がかかりすぎるアプリは OS によって終了されるため、OnNavigatedTo ではなく Loaded で 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
            }
        }

この操作には何年もかかります。1 分あたり約 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

私はそれをすべて機能させました。他の人が述べたように、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 に答える
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

それが役立つことを願っています

于 2012-04-03T06:06:12.733 に答える
0

スレッドの問題があると思います。メイン プロセスでプログレス バーを更新する場合、それを更新することはできません。alwais が終了すると、関数の最後に更新される可能性があります。ウィンフォンが存在するかどうかはわかりませんが、バックグラウンドワーカーを使用してみてください

于 2012-04-03T06:04:06.947 に答える