Как показать ожидание, когда приложение WPF занято привязкой данных - PullRequest
29 голосов
/ 08 сентября 2011

У меня есть приложение WPF, использующее шаблон MVVM, который иногда должен показывать курсор ожидания, когда он занят выполнением чего-то, что пользователь должен ждать.Благодаря комбинации ответов на этой странице: отображать «Песочные часы», когда приложение занято , у меня есть решение, которое почти работает (хотя это не совсем MVVM по духу).Всякий раз, когда я делаю что-то отнимающее много времени в моих моделях представления, я делаю это:

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

(ShowWaitCursor () возвращает IDisposable, который показывает waitcursor, пока он не удаляется)установить какое-то свойство.Это свойство привязано в моем XAML, например, так:

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

Однако, поскольку это может быть длинный список объектов, а иногда со сложными шаблонами данных и т. Д., Фактическое связывание и рендеринг иногда занимает значительное количествовремени.Поскольку эта привязка происходит вне моего оператора using, ожидание исчезнет до того, как фактическое ожидание закончится для пользователя.

Поэтому мой вопрос заключается в том, как создать ожидание в приложении WPF MVVM, которое учитывает привязку данных

Ответы [ 4 ]

84 голосов
/ 19 сентября 2011

Ответ Исака у меня не сработал, потому что он не решил проблему того, как действовать, когда фактическое ожидание истекло для пользователя. Я закончил тем, что сделал это: каждый раз, когда я начинаю делать что-то длительное, я вызываю вспомогательный метод. Этот вспомогательный метод изменяет курсор, а затем создает DispatcherTimer, который будет вызываться, когда приложение бездействует. Когда он вызывается, он возвращает курсор мыши обратно:

/// <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();
          }
     }
}
9 голосов
/ 20 мая 2014

Так что мне не нравилось использовать 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>
7 голосов
/ 08 сентября 2011

В прошлом я определял логические свойства в модели представления, которые указывают на то, что выполняется длительный расчет.Например, IsBusy, для которого задано значение true при работе и значение false в режиме ожидания.

Затем в представлении я привязываюсь к этому и отображаю индикатор выполнения, или счетчик, или аналогичное, пока это свойство имеет значение true.Я лично никогда не устанавливал курсор, используя этот подход, но я не понимаю, почему это было бы невозможно.

Если вы хотите еще больше контроля, а простого логического значения недостаточно, вы можете использовать VisualStateManager , который вы запускаете из вашей модели представления.При таком подходе вы можете подробно указать, как должен выглядеть пользовательский интерфейс в зависимости от состояния модели представления.

1 голос
/ 24 октября 2011

В дополнение к вкладу Исак Саво, вы можете посмотреть на блог Брайана Китинга для рабочего образца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...