2012-01-03 7 views
8

私は、アプリケーションが「考える」の間にユーザーが待つ必要のある非常に重いアクションを実行するwpfアプリケーションを持っています。「ビジー」エフェクトオーバーレイ

私がしたいのは、アプリケーションのメインスレッドが考えている間に、別のスレッドがウィンドウ全体を無効にし、灰色がかった色を与え、円形の進行状況バーが画面の中央に表示されます。

これは大きな問題です。一般的なアイデアだけを行うには、コード全体を実際に必要としません。すべてのあなたの助けを

おかげ..

答えて

2

は、新しいスレッドに重いアクションをオフロードし、メインスレッド上でUIのもの(無効灰色とプログレスバー)を行います。 BackgroundWorker and Dispatcherを参照してください。

UI用の新しいスレッドを使用することは可能ですが、既存のウィンドウを使用することはできません。 UIコントロール(Dispatcher)は、それが属するスレッドによってオンラインで使用/呼び出すことができます。ただし、新しいスレッドを作成し、新しいDispatcherで新しいウィンドウを使用してUIの処理を行うことができます。新しいウィンドウを元のウィンドウに配置する必要があります。私の最初の提案ほど簡単ではありません。大量のアクションがいつ実行されるかわからない場合は、オプションになる可能性があります。 here,hereおよびhereを参照のこと。

+0

ありがとうございます、これは非常に役に立ちました! –

2

を使用することができ、ワーカースレッドのためのワーカースレッド

のうち、プログレスバーを非表示/ UIコンポーネントとショーの有効-プロパティを変更するにはサンプル:あなたがDoHeavyWorkを呼び出すと

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

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

私たちはいつもあるべきUIへのアクセスを持っているスレッドであると仮定します。 DisableWindowは、動作中に表示されるアニメーションなどを表示します。次に、新しいスレッドで実行される定義済みのデリゲートworkDelegateを呼び出し、完了したらコールバックはビューを復元する必要があります。

EnableWindowへの呼び出しは、UIにアクセスできるスレッドで行う必要があることに注意してください。

+0

ありがとう、これは非常に役に立ちました! –

+0

助けになるのはうれしいです。あなたは投票をして答えの一つを正解として受け入れることによってあなたの感謝を示すことができます。 –

12

上記の提案(バックグラウンドワーカー、Dispatcher)に加えて - はい、あなたが望むものを得るための正しいテクニックですが、あなたの質問であなたが要求したUI効果について議論しましょう。 MVVMパターンを使用している場合は、「私はビジー状態です」UIを作成し、ビューモデルのIsBusyプロパティにバインドしてUIを表示および非表示にすることができます。例えば:あなたのviewmodelにDoLongRunningOperation関数を呼び出すためにバックグラウンドワーカーやスレッドプールを使用するときにUIの使用でその後

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>  

正味の効果は、となります操作が開始/停止すると、Xamlで定義された境界線が表示/非表示になります。 WPFがスレッドマーシャリングを処理するときにディスパッチャを呼び出す必要はありません。

あまりにも多くのアニメーションを含むビジーコントロールの実装があります。ネット上でUIを魅力的にすることもあります。

お礼、

+0

ありがとう、私はいくつかのクールなアニメーションの実装をオンラインで感謝多くを見つけた –

+0

probs :)ただWPFグリッドを使用して直接別のコントロール(Z-インデックスの上位)にコントロールを配置することができます。これは、探しているグレーアウトエフェクトに非常に便利です。 –

関連する問題