J'utilise .Net 3.5 pour l'instant.Existe-t-il un meilleur moyen d'éviter une boucle infinie en utilisant des winforms?
À l'heure actuelle, j'utilise une astuce using
pour désactiver et activer les événements autour de certaines sections du code. L'utilisateur peut changer les jours, les heures, les minutes ou le nombre total de minutes, ce qui ne devrait pas provoquer une cascade infinie d'événements (par exemple, changement total des minutes, changement total des minutes, etc.)./façon plus directe. En connaissez-vous?
Pour les points musculeux:
Ce contrôle sera utilisé par plusieurs équipes - Je ne veux pas faire embarrassant. Je soupçonne que je n'ai pas besoin de réinventer la roue en définissant des heures dans un jour, des jours dans la semaine, etc. Une autre bibliothèque standard .Net là doit l'avoir. D'autres remarques concernant le code? Cette using (EventHacker.DisableEvents(this))
entreprise - qui doit être un modèle commun dans .Net ... changer le réglage temporairement. Quel est le nom? J'aimerais pouvoir y faire référence dans un commentaire et en lire plus sur les implémentations actuelles. Dans le cas général, non seulement il faut se souvenir d'une poignée de l'objet en cours de modification, mais aussi de l'état précédent (dans ce cas, l'état précédent n'a pas d'importance - les événements sont activés et désactivés de manière inconditionnelle). Ensuite, il y a aussi une possibilité de multi-threaded hacking
. On pourrait également utiliser des génériques pour rendre le code sans doute plus propre. Comprendre tout cela peut conduire à un article de blog de plusieurs pages. Je serais heureux d'entendre certaines des réponses.
P.S. Est-ce que j'ai l'impression de souffrir d'un trouble obsessionnel compulsif? Certaines personnes aiment faire avancer les choses et passer à autre chose; J'aime les garder ouvertes ... il y a toujours un meilleur moyen.
// Corresponding Designer class is omitted.
using System;
using System.Windows.Forms;
namespace XYZ // Real name masked
{
interface IEventHackable
{
void EnableEvents();
void DisableEvents();
}
public partial class PollingIntervalGroupBox : GroupBox, IEventHackable
{
private const int DAYS_IN_WEEK = 7;
private const int MINUTES_IN_HOUR = 60;
private const int HOURS_IN_DAY = 24;
private const int MINUTES_IN_DAY = MINUTES_IN_HOUR * HOURS_IN_DAY;
private const int MAX_TOTAL_DAYS = 100;
private static readonly decimal MIN_TOTAL_NUM_MINUTES = 1; // Anything faster than once per minute can bog down our servers.
private static readonly decimal MAX_TOTAL_NUM_MINUTES = (MAX_TOTAL_DAYS * MINUTES_IN_DAY) - 1; // 99 days should be plenty.
// The value above was chosen so to not cause an overflow exception.
// Watch out for it - numericUpDownControls each have a MaximumValue setting.
public PollingIntervalGroupBox()
{
InitializeComponent();
InitializeComponentCustom();
}
private void InitializeComponentCustom()
{
this.m_upDownDays.Maximum = MAX_TOTAL_DAYS - 1;
this.m_upDownHours.Maximum = HOURS_IN_DAY - 1;
this.m_upDownMinutes.Maximum = MINUTES_IN_HOUR - 1;
this.m_upDownTotalMinutes.Maximum = MAX_TOTAL_NUM_MINUTES;
this.m_upDownTotalMinutes.Minimum = MIN_TOTAL_NUM_MINUTES;
}
private void m_upDownTotalMinutes_ValueChanged(object sender, EventArgs e)
{
setTotalMinutes(this.m_upDownTotalMinutes.Value);
}
private void m_upDownDays_ValueChanged(object sender, EventArgs e)
{
updateTotalMinutes();
}
private void m_upDownHours_ValueChanged(object sender, EventArgs e)
{
updateTotalMinutes();
}
private void m_upDownMinutes_ValueChanged(object sender, EventArgs e)
{
updateTotalMinutes();
}
private void updateTotalMinutes()
{
this.setTotalMinutes(
MINUTES_IN_DAY * m_upDownDays.Value +
MINUTES_IN_HOUR * m_upDownHours.Value +
m_upDownMinutes.Value);
}
public decimal TotalMinutes
{
get
{
return m_upDownTotalMinutes.Value;
}
set
{
m_upDownTotalMinutes.Value = value;
}
}
public decimal TotalHours
{
set
{
setTotalMinutes(value * MINUTES_IN_HOUR);
}
}
public decimal TotalDays
{
set
{
setTotalMinutes(value * MINUTES_IN_DAY);
}
}
public decimal TotalWeeks
{
set
{
setTotalMinutes(value * DAYS_IN_WEEK * MINUTES_IN_DAY);
}
}
private void setTotalMinutes(decimal nTotalMinutes)
{
if (nTotalMinutes < MIN_TOTAL_NUM_MINUTES)
{
setTotalMinutes(MIN_TOTAL_NUM_MINUTES);
return; // Must be carefull with recursion.
}
if (nTotalMinutes > MAX_TOTAL_NUM_MINUTES)
{
setTotalMinutes(MAX_TOTAL_NUM_MINUTES);
return; // Must be carefull with recursion.
}
using (EventHacker.DisableEvents(this))
{
// First set the total minutes
this.m_upDownTotalMinutes.Value = nTotalMinutes;
// Then set the rest
this.m_upDownDays.Value = (int)(nTotalMinutes/MINUTES_IN_DAY);
nTotalMinutes = nTotalMinutes % MINUTES_IN_DAY; // variable reuse.
this.m_upDownHours.Value = (int)(nTotalMinutes/MINUTES_IN_HOUR);
nTotalMinutes = nTotalMinutes % MINUTES_IN_HOUR;
this.m_upDownMinutes.Value = nTotalMinutes;
}
}
// Event magic
public void EnableEvents()
{
this.m_upDownTotalMinutes.ValueChanged += this.m_upDownTotalMinutes_ValueChanged;
this.m_upDownDays.ValueChanged += this.m_upDownDays_ValueChanged;
this.m_upDownHours.ValueChanged += this.m_upDownHours_ValueChanged;
this.m_upDownMinutes.ValueChanged += this.m_upDownMinutes_ValueChanged;
}
public void DisableEvents()
{
this.m_upDownTotalMinutes.ValueChanged -= this.m_upDownTotalMinutes_ValueChanged;
this.m_upDownDays.ValueChanged -= this.m_upDownDays_ValueChanged;
this.m_upDownHours.ValueChanged -= this.m_upDownHours_ValueChanged;
this.m_upDownMinutes.ValueChanged -= this.m_upDownMinutes_ValueChanged;
}
// We give as little info as possible to the 'hacker'.
private sealed class EventHacker : IDisposable
{
IEventHackable _hackableHandle;
public static IDisposable DisableEvents(IEventHackable hackableHandle)
{
return new EventHacker(hackableHandle);
}
public EventHacker(IEventHackable hackableHandle)
{
this._hackableHandle = hackableHandle;
this._hackableHandle.DisableEvents();
}
public void Dispose()
{
this._hackableHandle.EnableEvents();
}
}
}
}
Personnellement, je n'aime pas cette utilisation de ** using **. C'est mignon et intelligent comment vous re-proposant une construction de langage, mais ce ne sont pas des traits de bon code. Vous obtenez un code légèrement plus propre au détriment de la compréhensibilité générale (considérez les programmeurs novices qui regardent votre code). J'utiliserais simplement try..finally blocks, rendant le code plus auto-documenté. –
Hm, vous pouvez avoir un point. J'ai vu ce (ab) usage employé par d'autres mais dans un différent de. D'autres l'aiment parce qu'elle économise la frappe. Personnellement, je pense qu'il faut un programmeur C++ novice plus long pour s'appuyer sur des auto-pointeurs qu'un programmeur novice C# pour apprendre ce 'mignon' comme vous le dites. Je ne suis pas sûr que le code soit optimisé pour la maintenance par des développeurs juniors, seniors ou chevronnés. Encore une fois, mon opinion biaisée contre la vôtre - je suis curieux de savoir ce que les autres ont à dire. –