2013-05-29 3 views
0

J'essaie d'implémenter un système d'avertissement lorsqu'un utilisateur essaie de faire une action illégale dans mon formulaire. L'idée est d'appeler la méthode StatusBarFade, donnez-lui le paramètre qu'il doit écrire, que d'avoir cette méthode afficher le texte, le faire clignoter en changeant sa couleur pendant une seconde et demi, puis rester une seconde et demie, après quoi le le texte disparaîtra.Texte clignotant dans la barre d'état

Le clignotement fonctionne une fois sur deux, tandis que le texte disparaît normalement. S'il vous plaît noter que je sais que ce code est assez salissant et il ya sûrement une meilleure façon de le faire, mais comme je ne sais pas exactement comment les délégués travaillent, je ne sais pas comment les utiliser correctement. J'espère que quelqu'un sera en mesure d'expliquer ce que je fais mal. Quoi qu'il en soit, après quelques tests, j'ai réalisé qu'il était préférable d'avoir deux minuteurs. Le problème est que ce code fonctionne toutes les deux fois.

private Timer timer = new System.Timers.Timer(); 
    private Timer timerColor = new System.Timers.Timer(); 
    private void StatusBarFade(string ispis) 
    { 
     statusBar1AS2.Content = ispis; 
     int i = 0; 
     timerColor.Interval = 100; 
     timerColor.AutoReset = true; 
     timerColor.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e) 
     { 
      this.Dispatcher.BeginInvoke(new Action(() => 
       { 
        ++i; 
        if (statusBar1AS2.Foreground == Brushes.Black) 
         statusBar1AS2.Foreground = Brushes.Gold; 
        else 
         statusBar1AS2.Foreground = Brushes.Black; 
        if (i > 15) 
        { 
         statusBar1AS2.Foreground = Brushes.Black; 
         i = 0; 
         timerColor.Stop(); 
        } 
       })); 
     }; 
     timerColor.Start(); 

     timer.Interval = 3000; 
     timer.Elapsed += delegate(object sender, System.Timers.ElapsedEventArgs e) 
     { 
      timer.Stop(); 
      this.Dispatcher.BeginInvoke(new Action(() => { statusBar1AS2.Content = ""; })); 
     }; 
     timer.Start(); 
    } 

Pour autant que je comprends les délégués, je ne devrais pas être en ajoutant le même délégué à l'événement timer.Elapsed chaque fois que le texte est modifié, mais une seule fois, dans le constructeur, par exemple. Le problème est que je ne sais pas comment utiliser le compteur i comme je l'ai fait dans le code.

Répondre

4

Vous pouvez simplement utiliser l'animation suivante:

var animation = new ColorAnimation 
{ 
    From = Colors.Black, 
    To = Colors.Gold, 
    AutoReverse = true, 
    Duration = TimeSpan.FromSeconds(0.1), 
    RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(1.5)) 
}; 

animation.Completed += (o, e) => statusBar.Content = string.Empty; 

statusBar.Foreground = new SolidColorBrush(); 
statusBar.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, animation); 

MISE À JOUR: Afin de retarder la suppression du message, vous pouvez bien sûr utiliser une minuterie. Vous pourriez peut-être écrire votre méthode StatusBarFade comme indiqué ci-dessous, avec un DispatcherTimer:

private void StatusBarFade(string message) 
{ 
    statusBar.Content = message; 

    var animation = new ColorAnimation 
    { 
     From = Colors.Gold, 
     To = Colors.Black, 
     AutoReverse = true, 
     Duration = TimeSpan.FromSeconds(0.1), 
     RepeatBehavior = new RepeatBehavior(TimeSpan.FromSeconds(1.5)), 
    }; 

    statusBar.Foreground = new SolidColorBrush(); 
    statusBar.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, animation); 

    var timer = new DispatcherTimer 
    { 
     Interval = TimeSpan.FromSeconds(4.5) 
    }; 

    timer.Tick += 
     (o, e) => 
     { 
      timer.Stop(); 
      statusBar.Content = string.Empty; 
     }; 

    timer.Start(); 
} 
+0

Alors je voudrais créer l'animation le constructeur, puis modifiez la propriété statusBar.Foreground dans la méthode StatusBarFade? Pour autant que je puisse voir, cela clignotera le texte pendant une seconde et demie, et puis enlèvera le texte, n'est-ce pas? J'ai besoin que le texte clignote pendant 1,5 secondes, puis reste pendant X (probablement 3) secondes avant d'être retiré. Pourrais-je créer une animation composite, ou devrais-je simplement utiliser cette animation en combinaison avec la minuterie utilisée pour supprimer le texte dans le code ci-dessus? – user2352164

+0

Voir mon edit pour une suggestion de comment écrire votre méthode. – Clemens

0

essayez avec storyboard.

<Storyboard x:Key="TestBlinkStoryboard" AutoReverse="True" RepeatBehavior="Forever"> 
     <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(TextElement.Foreground).(SolidColorBrush.Color)" Storyboard.TargetName="textBlock"> 
      <EasingColorKeyFrame KeyTime="0" Value="Black"/> 
      <EasingColorKeyFrame KeyTime="0:0:0.5" Value="#FFE91414"> 
       <EasingColorKeyFrame.EasingFunction> 
        <BounceEase EasingMode="EaseInOut"/> 
       </EasingColorKeyFrame.EasingFunction> 
      </EasingColorKeyFrame> 
     </ColorAnimationUsingKeyFrames> 
    </Storyboard> 
0

@ La réponse de Clemens est ce que vous cherchez. Je voulais juste trouver la raison de ce comportement.

Le problème que vous rencontrez est dû au fait d'attacher des délégués sans les supprimer une fois qu'une itération de la minuterie est terminée.

Ainsi, vous voyez ce comportement sur chaque occurrence paire, car à ce moment-là, même le nombre de délégués est attaché à l'événement écoulé du temporisateur et donc il augmente sensiblement par incréments de 2,4,6, ... Ainsi se termine aller de Black -> Black et nous ne voyons jamais le passage à l'or. le temps global de l'animation diminue également progressivement de la même manière. C'était le problème.

Fix pour ce serait (s'il vous plaît ne le font pas utiliser. Il suffit de le voir comme un cas. Utiliser l'approche @Clemens ou ont le storyboard en XAML directement)

private int i = 0; 

private void StatusBarFade(string ispis) { 
    i = 0; 
    statusBar1AS2.Content = ispis; 
    timerColor.Interval = 100; 
    timerColor.AutoReset = true; 
    timerColor.Elapsed += TimerColorOnElapsed; 
    timerColor.Start(); 
} 

private void TimerColorOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs) { 
    Dispatcher.BeginInvoke(
    (new Action(
    () => { 
     ++i; 
     statusBar1AS2.Foreground = i % 2 == 0 || i > 15 ? Brushes.Black : Brushes.Gold; 
     if (i < 30) 
      return; 
     timerColor.Stop(); 
     timerColor.Elapsed -= TimerColorOnElapsed; 
     statusBar1AS2.Content = string.Empty; 
     }))); 
} 
Questions connexes