2012-01-03 31 views
8

Mam aplikację wpf, która wykonuje bardzo ciężkie działania, w których użytkownik musi czekać, aż aplikacja "myśli"."Zajęta" nakładka efektów

Co chcę zrobić, gdy główny wątek aplikacji myśli, inny wątek wyłączy całe okno i nadadzą mu szarawy kolor, a na środku ekranu pojawi się okrągły pasek postępu.

Jest to bardzo ważne pytanie i naprawdę nie potrzebuję całego kodu, aby zrobić to tylko ogólną ideą.

Dzięki za pomoc ..

Odpowiedz

2

odciążyć ciężkich działań do nowego wątku i robić rzeczy UI (wyłącz, szary na zewnątrz i pasek postępu) na głównym wątku. Zobacz BackgroundWorker and Dispatcher.

Używanie nowego wątku dla elementów interfejsu użytkownika jest możliwe, ale nie można korzystać z istniejącego okna. Kontrolkę interfejsu użytkownika (Dispatchera) można używać/wywoływać w trybie online przez wątek, do którego należy. Można jednak utworzyć nowy wątek i użyć nowego okna z nowym Dispatcherem, aby zrobić rzeczy interfejsu użytkownika. Będziesz wtedy musiał ustawić nowe okno na oryginale. Nie tak łatwe, jak moja pierwsza sugestia. Może to być opcja, jeśli nie wiesz, kiedy wykonywana jest ciężka akcja. Zobacz here, here i here.

+0

Dziękuję bardzo, to było bardzo pomocne! –

2

Spójrz na to próbka:

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

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

po wywołaniu DoHeavyWork Zakładam, że jesteśmy na wątku, który ma dostęp do interfejsu użytkownika, który powinien być zwykle. DisableWindow pokazuje animację lub cokolwiek, co powinno być widoczne podczas pracy. Następnie wywołujesz predefiniowanego delegata, workDelegate, który będzie działał na nowym wątku, a po jego zakończeniu wywołanie zwrotne powinno przywrócić widok.

Należy pamiętać, że wywołanie EnableWindow należy wykonać w wątku, który ma dostęp do interfejsu użytkownika.

+0

Dziękuję bardzo, to było bardzo pomocne! –

+0

Cieszę się, że mogę pomóc. Możesz wyrazić swoje podziękowania za głosowanie w górę i zaakceptować jedną z odpowiedzi jako poprawną odpowiedź. –

12

Oprócz powyższych sugestii (pracownik w tle, dyspozytor) - tak, to są poprawne techniki, aby uzyskać to, czego chcesz, ale pozwól mi omówić efekt interfejsu, o który prosiłeś w swoim pytaniu. Jeśli używasz wzorca MVVM, możesz utworzyć interfejs użytkownika "Jestem zajęty" i powiązać z właściwością IsBusy w modelu widoku, aby pokazać i ukryć interfejs użytkownika. Na przykład:

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; 
     } 
    } 
} 

następnie w użyciu interfejs ten XAML (lub podobny)

<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>  

Efekt netto będzie podczas korzystania pracownikowi tła lub puli wątków, aby wywołać funkcję DoLongRunningOperation w viewmodel, granica zdefiniowana w Xaml będzie się wyświetlać/ukrywać podczas startu/zatrzymania operacji. Nie będziesz potrzebował dyktafonu do wywoływania tutaj, ponieważ WPF obsługuje ci systemowanie wątków.

Istnieją implementacje zajętych kontrolek z animacjami typu whirlygig, itp. ... również w Internecie, aby urozmaicić interfejs użytkownika.

Pozdrawiam,

+0

Dziękuję, znalazłem kilka fajnych implementacji animacji online dziękuję bardzo –

+0

Brak problemów :) Po prostu zauważ, że możesz użyć siatki WPF, aby umieścić kontrolkę bezpośrednio nad inną kontrolką (wyżej w indeksie Z). Jest to bardzo przydatne dla efektu szarego, którego szukasz. –