28

シナリオ:

  • ユーザーがビューのボタンをクリックします
  • これにより、ViewModel、DoProcessingでコマンドが呼び出されます

ViewとViewModelの責任を考慮して、待機カーソルはどのように、どこに設定されますか?

明確にするために、コマンドの実行中にDEFAULTカーソルを砂時計に変更しようとしています。コマンドが完了すると、カーソルのミュートが矢印に戻ります。(これは私が探している同期操作であり、UIをブロックしたいです)。

ViewModelにIsBusyプロパティを作成しました。アプリケーションのマウスポインタが変更されていることを確認するにはどうすればよいですか?

4

8 に答える 8

35

私は自分のアプリケーションでそれをうまく使用しています:

/// <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, System.Windows.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();
        }
    }
}

これはここから取られました。Courtsey huttelihut .

SetBusyState時間のかかる操作を実行すると思われるたびに、メソッドを呼び出す必要があります。例えば

...
UIServices.SetBusyState();
DoProcessing();
...

これにより、アプリケーションがビジー状態のときはカーソルが待機カーソルに自動的に変更され、アイドル状態のときは通常の状態に戻ります。

于 2012-04-12T11:46:07.803 に答える
13

非常に簡単な方法は、ウィンドウ (またはその他のコントロール) の「カーソル」プロパティに単純にバインドすることです。例えば:

XAML:

<Window
    x:Class="Example.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     Cursor="{Binding Cursor}" />

ViewModel Cursor プロパティ (Apex.MVVM を使用):

    private NotifyingProperty cursor = new NotifyingProperty("Cursor", typeof(System.Windows.Input.Cursor), System.Windows.Input.Cursors.Arrow);
    public System.Windows.Input.Cursor Cursor
    {
        get { return (System.Windows.Input.Cursor)GetValue(cursor); }
        set { SetValue(cursor, value); }
    }

次に、必要に応じてビュー内のカーソルを変更するだけです...

    public void DoSomethingLongCommand()
    {
        Cursor = System.Windows.Input.Cursors.Wait;

        ... some long process ...

        Cursor = System.Windows.Input.Cursors.Arrow;
    }
于 2014-02-13T15:22:01.817 に答える
2

コマンドはビュー モデルで処理されるため、合理的な決定は次のようにすることです。

1) ビジー インジケーター サービスを作成し、それをビュー モデルに挿入します (これにより、カーソル ロジックを厄介なアニメーションに簡単に置き換えることができます)。

2) コマンド ハンドラで、ビジー インジケータ サービスを呼び出して、ユーザに通知します。

私は間違っているかもしれませんが、UI スレッドで重い計算や I/O を実行しようとしているようです。この場合、スレッド プールで作業を行うことを強くお勧めします。Task と TaskFactory を使用して、ThreadPool で作業を簡単にラップできます

于 2012-04-12T07:42:56.107 に答える
0

私見では、ビューモデルのコマンドの隣に待機カーソル ロジックを配置してもまったく問題ありません。

カーソルを変更する最善の方法については、プロパティIDisposableを変更するラッパーを作成しMouse.OverrideCursorます。

public class StackedCursorOverride : IDisposable
{
    private readonly static Stack<Cursor> CursorStack;

    static StackedCursorOverride()
    {
        CursorStack = new Stack<Cursor>();
    }

    public StackedCursorOverride(Cursor cursor)
    {            
        CursorStack.Push(cursor);
        Mouse.OverrideCursor = cursor;            
    }

    public void Dispose()
    {
        var previousCursor = CursorStack.Pop();
        if (CursorStack.Count == 0)
        {
            Mouse.OverrideCursor = null;
            return;
        }

        // if next cursor is the same as the one we just popped, don't change the override
        if ((CursorStack.Count > 0) && (CursorStack.Peek() != previousCursor))
            Mouse.OverrideCursor = CursorStack.Peek();             
    }
}

使用法:

using (new StackedCursorOverride(Cursors.Wait))
{
     // ...
}

上記は、この質問に投稿したソリューションの改訂版です。

于 2012-04-12T08:16:20.070 に答える