Попытка отобразить сообщение "Пожалуйста, подождите" в WPF во время длительной операции

У меня есть please waitTextBlock в моем XAML, чей Visibility собственность связана с IsBusy Свойство на моей ViewModel (которая реализует INotifyPropertyChanged). Отдельная кнопка запускает длительный (2-3 секунды) процесс, например:

IsBusy = true;

try
{
    // Do some long-running process
}

finally
{
    IsBusy = false;
}

Но please wait сообщение никогда не появляется Я предполагаю, что операция выполняется в потоке пользовательского интерфейса и, следовательно, не дает ей возможность обновить? Это работает, если я запускаю приведенный выше код в отдельном потоке, но я не хочу, чтобы пользователь что-либо делал во время выполнения операции - я рад, что пользовательский интерфейс freeze,

Как я могу отобразить please wait сообщение? Или мне лучше запустить его в фоновом потоке и (как-то) заблокировать пользовательский интерфейс на время? Я использую.Net 4 кстати.

3 ответа

Решение

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

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

Лучшим решением было бы связать IsEnabled вашей формы / окна /UserControl/ и т. д. в IsBusy имущество. Затем, когда она становится занятой, вся форма отключается, чтобы пользователь не мог ее изменить, не блокируя приложение.

Вначале Visibility собственность не boolтак что если вы хотите связать bool переменная к нему вам нужно использовать IValueConverterи, во-вторых, да, вы правы, в то время как поток пользовательского интерфейса занят вашей продолжительной операцией, он не будет выполнять ничего другого, включая изменение видимости.

Я бы предложил использовать WPF ToolkitBusyIndicator ожидайте поставить свою собственную панель, у нее есть IsBusy bool имущество.

Кроме того, Froozen UI не является удобным для пользователя, как правило, я использую этот фрагмент

IsBusy = true;
Task.Factory.StartNew(() => 
{ 
  // Do work. 
})
.ContinueWith(t=>IsBusy=false, 
                        TaskScheduler.FromCurrentSynchronizationContext());

Также обратите внимание, чтобы проверить ошибки в ContinueWith метод, или вы получите исключение на Task располагать

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

if (!YOURCONTROL.Dispatcher.CheckAccess())
{
    YOURCONTROL.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate()
        {
            //do something with the control/form/...
        }));
}
else
{
    //update your control
}
Другие вопросы по тегам