2012-01-03 2 views
8

У меня есть приложение wpf, которое выполняет очень тяжелые действия, в которых пользователю нужно ждать, пока приложение «думает».«Занят» Эффект Наложение

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

Это очень большой вопрос, и мне не нужен весь код, чтобы сделать это только общая идея.

Спасибо за вашу помощь ..

ответ

2

Разгрузка тяжелого действия на новый поток и сделать материал UI (отключить, серые, и прогресс бар) на главном потоке. См. BackgroundWorker and Dispatcher.

Использование новой темы для пользовательского интерфейса возможно, но без использования существующего окна. Элемент управления пользовательским интерфейсом (Dispatcher) может быть использован/вызван в потоке, к которому он принадлежит. Тем не менее вы могли создать новый поток и использовать новое окно с новым диспетчером для создания пользовательского интерфейса. Затем вам нужно будет позиционировать новое окно над оригиналом. Не так просто, как мое первое предложение. Это может быть вариант, если вы не знаете, когда выполняется тяжелое действие. См. here, here и here.

+0

Спасибо, это было очень полезно! –

3

Использование Dispatcher.BeginInvoke изменить Enable-свойства компонентов пользовательского интерфейса и показать/скрыть ProgressBar из рабочего потока

для рабоче-нить можно использовать BackgroundWorker-Class

+0

Большое спасибо, это было очень полезно! –

2

Взгляните на это образец:

public void DoHeavyWork() 
    { 
     mainDispatcher = Dispatcher.CurrentDispatcher; 
     DisableWindow(); 
     workDelegate.BeginInvoke(EnableWindowCallBack, null); 
    } 

    private void EnableWindowCallBack(IAsyncResult asyncResult) 
    { 
     workDelegate.EndInvoke(asyncResult); 
     mainDispatcher.InvokeIfRequired(() => { EnableWindow(); }); 
    } 

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

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

+0

Большое спасибо, это было очень полезно! –

+0

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

12

В дополнение к вышеуказанным предложениям (фоновый рабочий, диспетчер) - да, это правильные методы, чтобы получить то, что вы хотите, но позвольте мне обсудить эффект пользовательского интерфейса, который вы запросили в своем вопросе. Если вы используете шаблон MVVM, вы можете создать пользовательский интерфейс «Я занят» и привязать его к свойству IsBusy в модели представления, чтобы показать и скрыть пользовательский интерфейс. Например:

public class MyViewModel : INotifyPropertyChanged 
{ 
    // Bind to this property any UI you want to 
    // show/hide during long running updates 
    public bool IsBusy 
    { 
     get { return _isBusy; } 
     set 
     { 
      _isBusy = true; 
      OnPropertyChanged("IsBusy"); 
     } 
    } 

    private void OnPropertyChanged(string prop) 
    { 
     var handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(prop)); 
     } 
    } 

    // Note: This is intended to be called on a background thread 
    private void DoLongRunningOperationOnABackgroundThread() 
    { 
     try 
     { 
      IsBusy = true; 

      // do your work 
     } 
     finally 
     { 
      IsBusy = false; 
     } 
    } 
} 

Тогда в использовании пользовательского интерфейса этой XAML (или аналогичные)

<UserControl:MyControl x:Class="MyApp.MyControl" 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <UserControl.Resources> 
     <BooleanToVisibilityConverter x:Key="boolToVis"/> 
    </UserControl.Resources> 
    <Grid> 
     <!-- your UI code goes here --> 

     <!-- Below this, at higher Z-Order place a control to gray out the screen when IsBusy = true --> 
     <Border Background="#55000000" BorderThickness="0" Visibility="{Binding IsBusy, Converter={StaticResource boolToVis}}"> 
      <TextBlock Text="I AM BUSY!" Font-Size="32" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White"/> 
     </Border> 
    <Grid> 
</UserControl>  

Чистый эффект будет при использовании фона рабочего или ThreadPool вызвать функцию DoLongRunningOperation в вашем ViewModel, граница, определенная в Xaml, будет отображаться/скрываться при запуске/остановке операции. Вам не понадобится диспетчер для вызова здесь, поскольку WPF обрабатывает сортировку потоков для вас.

Существуют реалистичные элементы управления занятостью с анимацией whirlygig и т. Д. ... в сети, чтобы оживить интерфейс.

С уважением,

+0

Спасибо, я нашел несколько интересных анимационных реализаций в Интернете, спасибо большое –

+0

Нет проблем :) Просто обратите внимание, что вы можете использовать WPF Grid для размещения элемента управления непосредственно над другим элементом управления (выше в Z-Index). Это очень полезно для эффекта серого эффекта, который вы ищете. –

Смежные вопросы