C #, WPF, обновление графического интерфейса без помощников - PullRequest
2 голосов
/ 04 февраля 2010

У меня есть программа, которая запускается через 10-20 секунд. Мне нужно показать окно с индикатором выполнения при запуске программы. Я знаю, что BackgroundWorker - правильный способ сделать это, но, к сожалению, у меня нет времени, чтобы переработать весь графический интерфейс с использованием потоков прямо сейчас Вот код, который я пытаюсь, но он не работает. Кто-нибудь может помочь ..?

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();

            Thread t = new Thread(ShowLoadingWindow);
            t.SetApartmentState(ApartmentState.STA);
            t.Priority = ThreadPriority.Highest;
            t.Start();

            DoSomeLongTask();
            keepLooping = false;
        }

        bool keepLooping = true;
        private void ShowLoadingWindow()
        {
            LoadingWindow lw = new LoadingWindow();
            lw.Show();

            while (keepLooping)
            {
                Thread.Sleep(1);
            }

            lw.Close();
        }

        private void DoSomeLongTask()
        {
            for (int i = 0; i < 20000; i++)
            {
                GC.Collect();
            }
        }
    }
}

Окно загрузки - это просто пустое окно с индикатором выполнения. Как это не работает?

Ответы [ 3 ]

10 голосов
/ 04 февраля 2010

Вы все еще выполняете длинную задачу в главном потоке. Вам нужно показать окно загрузки в главном потоке и выполнить длинную задачу в фоновом режиме.

Использование BackgroundWorker действительно самое простое решение для этого:

BackgroundWorker bw;
LoadingWindow lw;

public Window1() {
    bw = new BackgroundWorker();
    lw = new LoadingWindow();

    bw.DoWork += (sender, args) => {
        // do your lengthy stuff here -- this will happen in a separate thread
        ...
    }

    bw.RunWorkerCompleted += (sender, args) => {
        if (args.Error != null)  // if an exception occurred during DoWork,
            MessageBox.Show(args.Error.ToString());  // do your error handling here

        // close your loading window here
        ...
    }

    // open and show your loading window here
    ...

    bw.RunWorkerAsync(); // starts the background worker
}
5 голосов
/ 04 февраля 2010

Это действительно очень просто использовать backgroundworker.

public partial class Window1 : Window
{
    BackgroundWorker worker = new BackgroundWorker();

    public Window1()
    {
        worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        worker.ReportsProgress = true;
        worker.ProgressChanged += new ProgressChangedEventHandler(update_progress);
    }


    void worker_DoWork(object sender, DoWorkEventArgs e){
        DoSomeLongTask();
        //call worker.ReportProgress to update bar
    }

    void update_progress(object sender, ProgressChangedEventArgs e)
    {
        myscrollbar.Value = e.Value;
    }
}

Главное, что нужно иметь в виду, это никогда не касаться графического интерфейса из метода DoWork. Это должно через ProgressChanged / ReportProgress

3 голосов
/ 04 февраля 2010

Если вам не нужен фоновый работник, вам нужно скорректировать код, чтобы выполнить длинную задачу в новом потоке.

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
      public Window1()
      {
          InitializeComponent();

          Thread t = new Thread(DoSomeLongTask);
          t.Start();

          // switch this with the DoSomeLongTask, so the long task is
          // on the new thread and the UI thread is free.
          ShowLoadingWindow();
    }
  }
}

Если вы хотите затем обновить индикатор выполнения из вашего метода «DoSomeLongTask», то вам нужно убедиться, что вы вызываете invoke. Например:

delegate void ProgressDelegate(int Progress);  
private void UpdateProgress( int  Progress)  
{  
   if (!progressBar1.Dispatcher.CheckAccess())  
   {  
     progressBar1.Value = Progress;  
   }  
   else  
   {  
     ProgressDelegate progressD = new ProgressDelegate(UpdateProgress);  
     progressBar1.Dispatcher.Invoke(progressD, new object[] { Progress });  
   }  
}  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...