2011-09-08 25 views
28

MVCパターンを使用してWPFアプリケーションを使用しているときに、ユーザーが待たなければならないときにwaitcursorを表示することがあります。このページの回答の組み合わせがあります:display Hourglass when application is busy、私はほとんどの作品を(実際にはMVVMではありませんが)解決しています。 私は私のviewmodelsで何か時間のかかる操作を行うたびに、私はこれを実行します。WPFアプリケーションがビジー状態のときにwaitcursorを表示する方法データバインディング

using (UiServices.ShowWaitCursor()) 
{ 
.. do time-consuming logic 
this.SomeData = somedata; 
} 

(ShowWaitCursorは()それは、処分されるまでwaitcursorを示しIDisposableインターを返します)ここで、I私の例の最後の行は、いくつかのプロパティを設定します。このプロパティは、XAMLでバインドされています(例:しかし

<ItemsControl ItemsSource="{Binding SomeData}" /> 

、これはオブジェクトの長いリスト可能性があり、時にはなどの複雑なdatatemplates、と実際の結合とレンダリングいつかはかなりの時間がかかるためこのような。このバインドは私のusingステートメントの外で行われるので、waitcursorは実際の待機がユーザのために終わる前に消え去ります。

私の質問は、データバインディングを考慮したWPF MVVMアプリケーションでwaitcursorを実行する方法です。

答えて

82

実際の待ち時間が終わったときの対処方法の問題を解決しなかったので、Isakの答えは私のためには機能しませんでした。 私はこれをやり終えました:毎回何か時間を掛けることを始めると、私はヘルパーメソッドを呼び出します。このヘルパーメソッドはカーソルを変更し、アプリケーションがアイドル状態のときに呼び出されるDispatcherTimerを作成します。それはバックmousecursorを設定し、呼ばれた場合:

/// <summary> 
/// Contains helper methods for UI, so far just one for showing a waitcursor 
/// </summary> 
public static class UiServices 
{ 

    /// <summary> 
    /// A value indicating whether the UI is currently busy 
    /// </summary> 
    private static bool IsBusy; 

    /// <summary> 
    /// Sets the busystate as busy. 
    /// </summary> 
    public static void SetBusyState() 
    { 
      SetBusyState(true); 
    } 

    /// <summary> 
    /// Sets the busystate to busy or not busy. 
    /// </summary> 
    /// <param name="busy">if set to <c>true</c> the application is now busy.</param> 
    private static void SetBusyState(bool busy) 
    { 
      if (busy != IsBusy) 
      { 
       IsBusy = busy; 
       Mouse.OverrideCursor = busy ? Cursors.Wait : null; 

       if (IsBusy) 
       { 
        new DispatcherTimer(TimeSpan.FromSeconds(0), DispatcherPriority.ApplicationIdle, dispatcherTimer_Tick, Application.Current.Dispatcher); 
       } 
      } 
    } 

    /// <summary> 
    /// Handles the Tick event of the dispatcherTimer control. 
    /// </summary> 
    /// <param name="sender">The source of the event.</param> 
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> 
    private static void dispatcherTimer_Tick(object sender, EventArgs e) 
    { 
      var dispatcherTimer = sender as DispatcherTimer; 
      if (dispatcherTimer != null) 
      { 
       SetBusyState(false); 
       dispatcherTimer.Stop(); 
      } 
    } 
} 
+0

グレート実装:

は、ここに私のソリューションです!これは、サードパーティのUIバインディング操作で時間の消費が起こっているときには完璧に機能します。いつ私は本当にそれが完了したか分からない。ありがとうございました! –

+0

これをboolではなくcountを使用するように変更します。そうすれば、複数の場所で待機カーソルが必要だと言うことができ、すべてが放棄されるまでそれが残されます。 –

+1

ニース!ありがとうございました! – Dummy01

6

過去に行ったことは、長時間の計算が進行中であることを示すビューモデル内のブール値プロパティを定義することです。たとえば、IsBusyは、動作時にはtrueに設定され、アイドル時にはfalseに設定されます。

このビューにバインドして、このプロパティがtrueのときにプログレスバーまたはスピナーなどを表示します。私は個人的にこのアプローチを使用してカーソルを設定していませんが、なぜそれが不可能であるかはわかりません。

さらに制御したいだけでブール値が単純でない場合は、ビューモデルからドライブするVisualStateManagerを使用できます。このアプローチでは、ビューモデルの状態に応じてUIをどのように見えるかを詳細に指定できます。

1

ISAKサボの貢献に加えて、あなたはワーキングサンプルのためBrian Keating's blogを見を持っている場合があります。

7

私は複数のウィンドウを持っていたので、現在は何かを実行していなかったウィンドウに通常の矢印カーソルがあるようにしたいので、OverrideCursorを使用したくありませんでした。

<Window.Style> 
    <Style TargetType="Window"> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding IsBusy}" Value="True"> 
       <Setter Property="Cursor" Value="Wait" /> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
</Window.Style> 
<Grid> 
    <Grid.Style> 
     <Style TargetType="Grid"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding IsBusy}" Value="True"> 
        <Setter Property="IsHitTestVisible" Value="False" /> <!-- Ensures wait cursor is active everywhere in the window --> 
        <Setter Property="IsEnabled" Value="False" /> <!-- Makes everything appear disabled --> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </Grid.Style> 
    <!-- Window controls go here --> 
</Grid> 
関連する問題