TextBlock не будет обновляться

У меня есть текстовый блок под названием «findListText». Здесь я обновляю текст в нем:

private void InstantSearch(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Return)
    {
        HitEnter = true;
    }
    findListText.Text = "Processing request. Please wait...";
    Find(bool.Parse("False" as string));
}

Однако следующий набор кода — это функция поиска, которая может занять до 10 секунд, а по ее окончании снова меняет текст в findListText.

private void Find(bool? bForward = true)
{
    {
        //Lots and lots of code
    }
    findListText.Text = "Search completed."
}

Проблема в том, что текстовый блок никогда не обновляется до «Обработка запроса. Пожалуйста, подождите…». Текстовый блок находится в исходном состоянии и через 10 секунд обновляется до «Поиск завершен», по-видимому, пропуская посредника.

Я использую С#-WPF. Что я здесь делаю неправильно?


person Robbo905    schedule 20.08.2012    source источник
comment
О какой технологии мы говорим? ВПФ? Выиграть формы? Веб-формы?   -  person Andre Calil    schedule 20.08.2012
comment
Что это за технология? WinForms, WPF, Silverlight, ASP.NET?   -  person ChrisF    schedule 20.08.2012
comment
Кстати, обратите внимание, что вам не нужен этот первый if. Просто измените его на HitEnter = e.Key == Key.Return;   -  person Andre Calil    schedule 20.08.2012
comment
Это форма xaml, а не веб-интерфейс. То есть WPF.   -  person Robbo905    schedule 20.08.2012


Ответы (5)


Неважно, о какой технологии я думаю.

Код выполняется в том же потоке, что означает, что пользовательский интерфейс не будет обновляться до тех пор, пока весь код в этом потоке не будет завершен. Вы должны обратиться к другому потоку, чтобы обновить этот текстовый блок.

В этом случае у вас будет 2 потока:

  • Исходный поток, выполняющий "много-много кода"
  • Второй (дополнительный) созданный поток, который будет обрабатывать обновление текста текстового блока, пока другой поток выполняет другой код.

Я создал кое-что, которое должно решить вашу проблему, это на основе этой страницы переполнения стека

person Terry    schedule 20.08.2012
comment
Я ожидаю, что это именно проблема, но я не уверен, как мне создать отдельный поток только для обновления текстового блока. - person Robbo905; 20.08.2012
comment
Вам все это не нужно, все, что вам нужно сделать, это обновить пользовательский интерфейс. Проверьте мой ответ и дайте мне любую обратную связь, пожалуйста. - person Andre Calil; 20.08.2012
comment
@AndreCalil: ваш ответ - это то, что описано здесь, за исключением того, что вы не проверяете, принадлежит ли объект потоку. - person Terry; 20.08.2012
comment
@djerry Я не понимаю, как предоставленную вами ссылку можно использовать в моей конкретной ситуации. Не могли бы вы прояснить это для меня? Спасибо. - person Robbo905; 20.08.2012
comment
Вы правы, это решение для немного другой проблемы. Я обновлю ответ и больше поработаю над приложением-решением. - person Terry; 20.08.2012
comment
@djerry Большое спасибо! Я с нетерпением жду ваших идей. Я просмотрел все другие ответы, и, кажется, ничто не соответствует проблеме. - person Robbo905; 20.08.2012
comment
Отредактированный пост, надеюсь, это решит его. Хорошее предложение от Афелиона, но чего-то не хватает. - person Terry; 20.08.2012
comment
@djerry Глупый компьютер не имеет возможности открытия .rar. Думаете, вы могли бы повторно загрузить его в виде почтового индекса, чтобы я мог его проверить? Спасибо. - person Robbo905; 20.08.2012
comment
@Djerry Вызывающий поток не может получить доступ к этому объекту, потому что им владеет другой поток. Кажется, если я использую ваш метод, он не может получить переменные из-за пределов этого потока, который я создал. - person Robbo905; 20.08.2012
comment
@djerry Действительно так. Я не знаком с этой ошибкой, но полагаю, что многие строки длинного кода также будут вызывать эту ошибку, а не только первую, которую найдет программа. - person Robbo905; 21.08.2012
comment
@djerry У меня есть таблица данных, в которую часто записываются результаты, и помимо этого они отображаются в пользовательском интерфейсе; нет. На самом деле, даже обязательно эти строки вызывают исключение. - person Robbo905; 21.08.2012
comment
При работе в этом пуле все, что влияет на пользовательский интерфейс, должно вызываться так же, как обновляется ваш текстовый блок. - person Terry; 21.08.2012
comment
@djerry Я понимаю это, но, как я уже упоминал ранее, даже строки, которые не влияют на пользовательский интерфейс, похоже, вызывают указанную ошибку. Я должен буду еще раз изучить его. - person Robbo905; 21.08.2012
comment
@djerry Я считаю, что вы дали мне правильный ответ, и это всего лишь случай методичного просмотра моего 1000-строчного кода и редактирования всего этого ... Весело! Спасибо за предложение дополнительной поддержки, но я думаю, что вы ответили на первоначальный вопрос. - person Robbo905; 21.08.2012

Поскольку это WPF, попробуйте следующее: после изменения текста на «Processgin» вызовите:

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { this.UpdateLayout(); }));

Это скажет потоку обновить пользовательский интерфейс как можно скорее.

person Andre Calil    schedule 20.08.2012
comment
@djerry Действительно. Однако, насколько мы знаем приложение, это один поток. - person Andre Calil; 20.08.2012
comment
У меня с этим смешанный успех. По сути, у меня есть две функции поиска, одна из которых занимает миллисекунды, а другая — 10 секунд. Если я использую эту строку кода для короткого поиска, появляется сообщение запроса на обработку, хотя бы на долю секунды. При использовании этой строки кода с длинным 10-секундным поиском ничего не происходит. - person Robbo905; 20.08.2012
comment
Это исправление в целом является удачным и не является правильным способом справиться с такими ситуациями. Подумайте об этом — как пользовательский интерфейс может обновляться, если поток пользовательского интерфейса занят выполнением работы? Именно для такой ситуации и был создан BackgroundWorker. - person steveg89; 20.08.2012
comment
@ Robbo905 Вы пробовали изменить текст перед длительной обработкой? - person Andre Calil; 20.08.2012
comment
@AndreCalil Действительно, сообщение запроса на обработку должно появиться до того, как будет выполнен какой-либо поиск. Как упоминалось ранее, это работает для очень короткого поиска, но не для 10-секундного поиска с зависанием. - person Robbo905; 20.08.2012
comment
@AndreCalil Кажется, это работает примерно в 2% случаев, проверяя это. Так что он действительно что-то делает, но не почти всегда. Как вы думаете, почему? - person Robbo905; 20.08.2012
comment
@ Robbo905 Прости, чувак, я не знаю, что может произойти. Я проведу здесь несколько тестов (снова) - person Andre Calil; 20.08.2012

Вот как запустить метод поиска в отдельном потоке.

private void InstantSearch(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Return)
    {
        HitEnter = true;
    }
    findListText.Text = "Processing request. Please wait...";
    BackgroundWorker tempWorker = new BackgroundWorker();
    tempWorker.DoWork += delegate
    {
       Find(bool.Parse("False" as string));
    };
    tempWorker.RunWorkerAsync();
}

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

private void Find(bool? bForward = true)
{
   {
       //Lots and lots of code
   }
   Dispatcher.BeginInvoke((Action) delegate {
      findListText.Text = "Search completed."
   });
}
person steveg89    schedule 20.08.2012

Вам следует изучить концепцию многопоточности пользовательского интерфейса WPF. Вызовите Dispatcher, чтобы изменить текстовое поле. Также поиск должен выполняться с ThreadPool.QueueWorkerItem.

// Start worker thread
ThreadPool.QueueUserWorkItem(state =>
{
    // Long running logic here
   findListText.Dispatcher.BeginInvoke(() => findListText.Text = "Processing request. Please wait...");
   Find(bool.Parse("False" as string)); 


    // Tip: Run change on GUI thread from the worker using the dispatcher
    findListText.Dispatcher.BeginInvoke(() => findListText.Text = "Search completed.");
});
person Myrtle    schedule 20.08.2012
comment
Я не знаю, с чего начать. Кажется, я получаю сообщение «System.Threading.ThreadPool» не содержит определения ошибки «QueueWorkerItem». - person Robbo905; 20.08.2012

Я вернулся к этому только сейчас и еще раз просмотрел Интернет в поисках подобных проблем. Для чего-то столь же простого, как отправка одного сообщения до того, как произойдет длительный процесс, я удивлен, что никто не предложил "Application.DoEvents();". Да, я знаю, что у него есть свои недостатки, и мой пользовательский интерфейс все равно будет зависать, но, по крайней мере, для моей ситуации это идеально подходит.

person Robbo905    schedule 24.08.2012
comment
Сказав это, он все еще не идеален. - person Robbo905; 24.08.2012