Почему второй поток пользовательского интерфейса замораживает первый? - PullRequest
2 голосов
/ 23 октября 2011

У меня есть приложение с двумя потоками пользовательского интерфейса и одним фоновым рабочим.Все работает отлично, за исключением того, что обработка ProgressChanged во втором потоке пользовательского интерфейса имитирует первый.Почему так происходит?Как я могу обойти это (я хочу, чтобы второй поток был заблокирован вместо основного потока пользовательского интерфейса)?

Часть класса MainWindow:

private SimulationWindow simulationWindow;

    public MainWindow()
    {
        InitializeComponent();
        Thread thread = new Thread(() =>
        {
            simulationWindow = new SimulationWindow();
            simulationWindow.Show();
            simulationWindow.Closed += (sender2, e2) =>
                      simulationWindow.Dispatcher.InvokeShutdown();
            Dispatcher.Run();
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

    private void start_Click(object sender, RoutedEventArgs e)
    {
        simulationWindow.Start();
    }

Часть класса SimulationWindow:

private BackgroundWorker bw;

public SimulationWindow()
{
    InitializeComponent();
    bw = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}

void bw_DoWork(object sender, DoWorkEventArgs e)
{
    //some complex computation will go here
    //Thread.Sleep(10000); <- both windows responsive, OK
    bw.ReportProgress(0);
}


void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    //some complex rendering will go here
    Thread.Sleep(10000); // this blocks main UI thread, why?
}

public void Start()
{
    bw.RunWorkerAsync();
}

private void doSth_Click(object sender, RoutedEventArgs e)
{
    Thread.Sleep(10000); // freezes simulationWindow, which was understandable
}

1 Ответ

6 голосов
/ 23 октября 2011

Вы звоните simulationWindow.Start() в основном потоке пользовательского интерфейса. Это означает, что BW запущен в этом потоке, что означает, что он захватывает SynchronizationContext основного потока пользовательского интерфейса и, таким образом, также вызывает ProgressChanged в этом потоке.

Вам нужно направить вызов на bw.RunWorkerAsync() во второй поток. Вы можете сделать это в SimulationWindow.Start(), вызвав this.Dispatcher.Invoke и передав bw.RunWorkerAsync() в качестве делегата. Затем он должен работать в вашем втором потоке окна, и события будут вызываться в этом потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...