L’objective est d’afficher les informations sur lesquelles l’application fonctionne. Je recherche donc un exemple d’implémentation intelligent d’un spinner de chargement utilisant WPF / MVVM.
J’ai écrit ce contrôle d’utilisateur qui peut aider, il affichera des messages avec une barre de progression en train de tourner pour montrer qu’il charge actuellement quelque chose.
Il possède deux propriétés de base auxquelles vous pouvez vous connecter.
Pour obtenir ceci:
Collez ceci dans un contrôle utilisateur:
Pour obtenir un effet de disparition ColorAnimationUsingKeyFrames
sur chaque ellipse, ajoutez ce qui suit après chaque élément ColorAnimationUsingKeyFrames
. Assurez-vous de le diriger vers l’ellipse correcte.
Un très simple “plug and play” spinner pourrait être l’une des icons tournantes du package Font Awesome Wpf ( icons Spinning ).
L’utilisation est assez simple, installez simplement le paquet nuget:
PM> Install-Package FontAwesome.WPF
Puis ajoutez la référence à l’espace de noms
xmlns:fa="http://schemas.fontawesome.io/icons/"
et utilisez le contrôle ImageAwesome. Définissez la propriété Spin = “True” et sélectionnez l’une des icons “Spinner”, “Refresh”, “Cog” et “CircleOutlinedNotched”. Il est évolutif et peut être redimensionné en définissant la largeur et la hauteur.
Résumé visuel des options pour les icons tournantes. Enregistré en utilisant Screen To Gif .
Documentation sur GitHub .
Installer via NuGet:
PM> Install-Package FontAwesome.WPF
Ressemble à ça:
XAML:
Les icons illustrées sont Spinner
, CircleOutlineNotch
, Refresh
et Cog
. Il y en a beaucoup d’autres .
XAML copier / coller.
Découvrez le BusyIndicator dans le WPF Toolkit étendu .
Ceci est une mise à jour du code donné par @HAdes pour paramétrer la taille, la hauteur et la taille de l’ellipse.
Cette implémentation devrait automatiquement calculer les angles, les largeurs et les hauteurs requirejs à la volée.
Le contrôle utilisateur est lié à lui-même (code-behind) qui prend en charge tous les calculs.
XAML
Code Behind (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; } } }
Utilisation de l’échantillon
utilisez un type enum pour indiquer l’état de votre ViewModel
public enum ViewModeType { Default, Busy //etc. }
alors dans votre classe de base ViewModels, utilisez une propriété
public ViewModeType ViewMode { get { return this.viewMode; } set { if (this.viewMode != value) { this.viewMode = value; //You should notify property changed here } } }
et en vue déclencher le ViewMode et s’il est occupé show
Voici un exemple de solution tout en xaml. Il se lie à un booléen “IsWorking” dans la vue pour afficher le contrôle et lancer l’animation.
Dans WPF, vous pouvez maintenant faire simplement:
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
Ce repo sur github semble bien faire le travail:
https://github.com/blackspikeltd/Xaml-Spinners-WPF
Les essoreuses sont légères et peuvent facilement être placées partout où cela est nécessaire. Il y a un exemple de projet inclus dans le repo qui montre comment les utiliser.
Pas de méchant derrière les codes avec beaucoup de logique non plus. Si la prise en charge de MVVM est nécessaire, il suffit de les prendre et de les lancer dans une grid avec une liaison de visibilité.
CircularProgressBarBlue.xaml
CircularProgressBarBlue.xaml.cs
en utilisant le système;
en utilisant System.Windows;
en utilisant 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 { } } }