tutorial implementar como beginner advantages wpf mvvm

implementar - Cómo mostrar un waitcursor cuando la aplicación WPF está ocupada enlazando datos



wpf c# mvvm (4)

Además de la contribución de Isak Savo, es posible que desee echar un vistazo al blog de Brian Keating para una muestra de trabajo.

Tengo una aplicación WPF que usa el patrón MVVM que a veces tiene que mostrar un waitcursor cuando está ocupado haciendo algo que el usuario tiene que esperar. Gracias a una combinación de respuestas en esta página: mostrar Hourglass cuando la aplicación está ocupada , tengo una solución que casi funciona (aunque realmente no es MVVM en espíritu). Cada vez que hago algo que consume mucho tiempo en mis modelos de vista, hago esto:

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

(ShowWaitCursor () devuelve un IDisposable que muestra el waitcursor hasta que se desecha). La última línea en mi ejemplo es donde establezco alguna propiedad. Esta propiedad está vinculada en mi XAML, por ejemplo, de esta manera:

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

Sin embargo, dado que esto podría ser una larga lista de objetos y, a veces, con plantillas de datos complejas, etc., la vinculación real y la renderización en algún momento requieren una cantidad considerable de tiempo. Dado que este enlace se realiza fuera de mi declaración de uso, el waitcursor desaparecerá antes de que la espera real finalice para el usuario.

Entonces mi pregunta es ¿cómo hacer un waitcursor en una aplicación WPF MVVM que tenga en cuenta el enlace de datos?


Así que no me gustó usar OverrideCursor porque tenía varias ventanas y quería que las que no estaban ejecutando algo tuvieran el cursor de flecha normal.

Aquí está mi solución:

<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>


La respuesta de Isak no funcionó para mí, porque no resolvió el problema de cómo actuar cuando termina la espera real para el usuario. Terminé haciendo esto: cada vez que empiezo a hacer algo que me lleva mucho tiempo, llamo a un método de ayuda. Este método de ayuda cambia el cursor y luego crea un DispatcherTimer que se llamará cuando la aplicación esté inactiva. Cuando se lo llama, restablece el 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(); } } }


Lo que hice en el pasado es definir propiedades booleanas en el modelo de vista que indica que un cálculo largo está en progreso. Por ejemplo, IsBusy que se establece en verdadero cuando funciona y falso cuando está inactivo.

Luego, en la vista, me conecto a esto y visualizo una barra de progreso o una ruleta o similar mientras esta propiedad es verdadera. Personalmente, nunca puse el cursor usando este enfoque, pero no veo por qué no sería posible.

Si desea aún más control y un booleano simple no es suficiente, puede usar el VisualStateManager que maneja desde su modelo de vista. Con este enfoque, puede especificar en detalle cómo debería verse la interfaz de usuario dependiendo del estado del modelo de vista.