WPF caricamento spinner

L’objective è visualizzare le informazioni sul funzionamento dell’applicazione. Quindi sto cercando un esempio di implementazione intelligente di uno spinner di caricamento usando WPF / MVVM.

Ho scritto questo controllo utente che può aiutare, mostrerà messaggi con una barra di avanzamento che gira per mostrare che sta attualmente caricando qualcosa.

 

Ha un paio di proprietà di base a cui è ansible legarsi.

Per ottenere questo:

inserisci la descrizione dell'immagine qui

Attaccalo in un controllo utente:

                         

Per ottenere un effetto di scomparsa su ogni ellisse, aggiungi quanto segue dopo ciascun elemento ColorAnimationUsingKeyFrames . Assicurati di puntarlo verso l’ellisse corretta ..

                   

Uno spinner “plug and play” molto semplice potrebbe essere una delle icone rotanti del pacchetto Font Awesome Wpf ( icone rotanti ).

L’utilizzo è abbastanza semplice, basta installare il pacchetto nuget:

 PM> Install-Package FontAwesome.WPF 

Quindi aggiungi il riferimento allo spazio dei nomi

 xmlns:fa="http://schemas.fontawesome.io/icons/" 

e usa il controllo ImageAwesome. Imposta la proprietà Spin = “True” e seleziona una delle icone “Spinner”, “Refresh”, “Cog” e “CircleOutlinedNotched”. È scalabile e può essere ridimensionato impostando la larghezza e l’altezza.

      

Con immagini

Riepilogo visivo delle opzioni per le icone rotanti. Registrato usando Screen To Gif .


Font-Impressionante WPF

Documentazione su GitHub .

Installa tramite NuGet:

PM> Install-Package FontAwesome.WPF

Somiglia a questo:

XAML:

  

Le icone raffigurate sono Spinner , CircleOutlineNotch , Refresh e Cog . Ce ne sono molti altri


Metodo da @HAdes

Copia / incolla XAML.

Dai un’occhiata a BusyIndicator nel toolkit WPF esteso .

Questo è un aggiornamento del codice fornito da @HAdes per parametrizzare la larghezza, l’altezza e le dimensioni dell’ellisse.

Questa implementazione dovrebbe calcolare automaticamente angoli, larghezze e altezze richiesti al volo.

Il controllo utente è vincolato a sé stesso (code-behind) che si occupa di tutti i calcoli.

XAML

                           

Codice dietro (C #)

 using System; using System.Windows; using System.Windows.Controls; namespace WpfApplication2 { ///  /// Interaction logic for Spinner.xaml ///  public partial class Spinner : UserControl { public int EllipseSize { get; set; } = 8; public int SpinnerHeight { get; set; } = 0; public int SpinnerWidth { get; set; } = 0; // start positions public EllipseStartPosition EllipseN { get; private set; } public EllipseStartPosition EllipseNE { get; private set; } public EllipseStartPosition EllipseE { get; private set; } public EllipseStartPosition EllipseSE { get; private set; } public EllipseStartPosition EllipseS { get; private set; } public EllipseStartPosition EllipseSW { get; private set; } public EllipseStartPosition EllipseW { get; private set; } public EllipseStartPosition EllipseNW { get; private set; } public Spinner() { InitializeComponent(); } private void initialSetup() { float horizontalCenter = (float)(SpinnerWidth / 2); float verticalCenter = (float)(SpinnerHeight / 2); float distance = (float)Math.Min(SpinnerHeight, SpinnerWidth) /2; double angleInRadians = 44.8; float cosine = (float)Math.Cos(angleInRadians); float sine = (float)Math.Sin(angleInRadians); EllipseN = newPos(left: horizontalCenter, top: verticalCenter - distance); EllipseNE = newPos(left: horizontalCenter + (distance * cosine), top: verticalCenter - (distance * sine)); EllipseE = newPos(left: horizontalCenter + distance, top: verticalCenter); EllipseSE = newPos(left: horizontalCenter + (distance * cosine), top: verticalCenter + (distance * sine)); EllipseS = newPos(left: horizontalCenter, top: verticalCenter + distance); EllipseSW = newPos(left: horizontalCenter - (distance * cosine), top: verticalCenter + (distance * sine)); EllipseW = newPos(left: horizontalCenter - distance, top: verticalCenter); EllipseNW = newPos(left: horizontalCenter - (distance * cosine), top: verticalCenter - (distance * sine)); } private EllipseStartPosition newPos(float left, float top) { return new EllipseStartPosition() { Left = left, Top = top }; } protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { if(e.Property.Name == "Height") { SpinnerHeight = Convert.ToInt32(e.NewValue); } if (e.Property.Name == "Width") { SpinnerWidth = Convert.ToInt32(e.NewValue); } if(SpinnerHeight > 0 && SpinnerWidth > 0) { initialSetup(); } base.OnPropertyChanged(e); } } public struct EllipseStartPosition { public float Left { get; set; } public float Top { get; set; } } } 

Esempio di utilizzo

      

Ecco un esempio di una soluzione all-xaml. Si lega a un booleano “IsWorking” nel viewmodel per mostrare il controllo e avviare l’animazione.

                      

usa un tipo enum per indicare lo stato del tuo ViewModel

 public enum ViewModeType { Default, Busy //etc. } 

quindi nella class ViewModels Base utilizzare una proprietà

 public ViewModeType ViewMode { get { return this.viewMode; } set { if (this.viewMode != value) { this.viewMode = value; //You should notify property changed here } } } 

e in vista triggersre il ViewMode e se è occupato mostra busyindicator:

    

In WPF, ora puoi semplicemente fare:

 Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait; // set the cursor to loading spinner Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow; // set the cursor back to arrow 

Questo repo su github sembra fare abbastanza bene il lavoro:

https://github.com/blackspikeltd/Xaml-Spinners-WPF

I filatori sono tutti leggeri e possono essere facilmente posizionati ovunque sia necessario. C’è un progetto di esempio incluso nel repository che mostra come usarli.

Neanche code-behinds cattivi con un po ‘di logica. Se è necessario il supporto MVVM, è ansible prenderli e gettarli in una griglia con un binding Visibility.

CircularProgressBarBlue.xaml

              

CircularProgressBarBlue.xaml.cs

usando il sistema;

usando System.Windows;

using System.Windows.Media.Animation;

  ///  /// Interaction logic for CircularProgressBarBlue.xaml ///  public partial class CircularProgressBarBlue { private Storyboard _sb; public CircularProgressBarBlue() { InitializeComponent(); StartStoryBoard(); IsVisibleChanged += CircularProgressBarBlueIsVisibleChanged; } void CircularProgressBarBlueIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { if (_sb == null) return; if (e != null && e.NewValue != null && (((bool)e.NewValue))) { _sb.Begin(); _sb.Resume(); } else { _sb.Stop(); } } void StartStoryBoard() { try { _sb = (Storyboard)TryFindResource("spinning"); if (_sb != null) _sb.Begin(); } catch { } } } 

Lo spinner personalizzato pubblicato da @Menol aveva un piccolo problema in cui lo spinner sarebbe stato spostato verso il basso e verso destra dalla dimensione di un punto. Ho aggiornato il codice in modo che compensi questo offset sottraendo la metà del punto.

Ecco il codice aggiornato:

  private void initialSetup() { float horizontalCenter = (float)(SpinnerWidth / 2); float verticalCenter = (float)(SpinnerHeight / 2); float distance = (float)Math.Min(SpinnerHeight, SpinnerWidth) / 2; float dotComp = (float)(EllipseSize / 2); double angleInRadians = 44.8; float cosine = (float)Math.Cos(angleInRadians); float sine = (float)Math.Sin(angleInRadians); EllipseN = newPos(left: horizontalCenter - dotComp, top: verticalCenter - distance - dotComp); EllipseNE = newPos(left: horizontalCenter + (distance * cosine) - dotComp, top: verticalCenter - (distance * sine) - dotComp); EllipseE = newPos(left: horizontalCenter + distance - dotComp, top: verticalCenter - dotComp); EllipseSE = newPos(left: horizontalCenter + (distance * cosine) - dotComp, top: verticalCenter + (distance * sine) - dotComp); EllipseS = newPos(left: horizontalCenter - dotComp, top: verticalCenter + distance - dotComp); EllipseSW = newPos(left: horizontalCenter - (distance * cosine) - dotComp, top: verticalCenter + (distance * sine) - dotComp); EllipseW = newPos(left: horizontalCenter - distance - dotComp, top: verticalCenter - dotComp); EllipseNW = newPos(left: horizontalCenter - (distance * cosine) - dotComp, top: verticalCenter - (distance * sine) - dotComp); }