Как показать waitcursor, когда приложение WPF занято привязкой данных
У меня есть приложение WPF, использующее шаблон MVVM, который иногда должен показывать waitcursor, когда он занят тем, что пользователь должен ждать. Благодаря сочетанию ответов на этой странице: отображает Песочные часы, когда приложение занято, у меня есть решение, которое почти работает (хотя это не действительно MVVM по духу).
Всякий раз, когда я делаю что-то много времени в своих моделях просмотра, я делаю это:
using (UiServices.ShowWaitCursor())
{
.. do time-consuming logic
this.SomeData = somedata;
}
(ShowWaitCursor() возвращает IDisposable, который показывает waitcursor, пока он не будет удален)
Последняя строка в моем примере - это то, где я устанавливаю некоторое свойство. Это свойство связано в моем XAML, например. например:
<ItemsControl ItemsSource="{Binding SomeData}" />
Однако, поскольку это может быть длинный список объектов, а иногда и сложных datatemplates и т.д., фактическая привязка и рендеринг когда-то занимают значительное количество времени. Поскольку это привязка занимает место вне моего оператора using, ожидающий курсор исчезнет до того, как фактическое ожидание закончится для пользователя.
Итак, мой вопрос заключается в том, как сделать waitcursor в приложении MVF MVF, которое учитывает привязку данных?
Ответы
Ответ 1
Ответ 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();
}
}
}
Ответ 2
Поэтому мне не нравилось использование 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>
Ответ 3
То, что я делал в прошлом, - это определение логических свойств в модели viewmodel, которая указывает, что выполняется длительный расчет. Например, IsBusy
, который установлен в true при работе и false при простоя.
Затем в представлении я привязываюсь к этому и показываю индикатор выполнения или счетчик или аналогичный, пока это свойство истинно. Я лично никогда не устанавливал курсор с использованием этого подхода, но я не понимаю, почему это было бы невозможно.
Если вам нужен еще больший контроль, а простого логического значения недостаточно, вы можете использовать VisualStateManager, который вы выберете из своей модели просмотра, При таком подходе вы можете подробно указать, как должен выглядеть пользовательский интерфейс в зависимости от состояния модели.
Ответ 4
В дополнение к вкладу Исака Саво, вы можете посмотреть блог Брайана Китинга для рабочего образца.