我现在正在使用.Net 3.5。
现在我正在使用using
技巧来禁用和启用某些代码段周围的事件。用户可以更改天,小时,分钟或总分钟,这不应该导致无限级联的事件(例如,分钟更改总计,总更改分钟等)虽然代码执行我想要的,但可能会有更好的/更直接的方式。你知道吗?
对于强壮点:
这个控件将由多个团队使用 - 我不想让它变得尴尬。我怀疑在一天中定义几小时,一周中的几天等时,我不需要重新发明轮子。其他一些标准的.Net库必须有它。关于代码的任何其他评论?这个using (EventHacker.DisableEvents(this))
业务 - 必须是.Net中的常见模式...暂时更改设置。它的名字是什么?我希望能够在评论中引用它,并阅读有关当前实现的更多信息。在一般情况下,不仅需要记住被更改的事物的句柄,而且还需要记住先前的状态(在这种情况下,先前的状态无关紧要 - 事件无条件地打开和关闭)。然后还有multi-threaded hacking
的可能性。人们还可以利用泛型来使代码更清晰。弄清楚这一切可以导致一个多页的博客文章。我很高兴听到一些答案。
P.S。看起来我是否患有强迫症?有些人喜欢把事情搞定并继续前进;我喜欢让它们保持开放......总有一种更好的方式。
// 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();
}
}
}
}
答案 0 :(得分:2)
我会使用布尔字段来阻止多次执行setTotalMinutes
方法,并将事件处理程序的创建移动到InitializeComponentCustom
方法。
这样的事情:
public partial class PollingIntervalGroupBox : GroupBox
{
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.
private bool _totalMinutesChanging;
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;
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;
}
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 totalMinutes)
{
if (_totalMinutesChanging) return;
try
{
_totalMinutesChanging = true;
decimal nTotalMinutes = totalMinutes;
if (totalMinutes < MIN_TOTAL_NUM_MINUTES)
{
nTotalMinutes = MIN_TOTAL_NUM_MINUTES;
}
if (totalMinutes > MAX_TOTAL_NUM_MINUTES)
{
nTotalMinutes = MAX_TOTAL_NUM_MINUTES;
}
// 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;
}
finally
{
_totalMinutesChanging = false;
}
}
}
答案 1 :(得分:2)
这看起来不太好。客户端代码不知道为什么它会禁用它看不到的私有控件上的事件。也没有办法让它看到公共财产发生变化,没有事件可以说公共财产改变了价值。如果它想忽略更改事件,那么它只会取消订阅或忽略那些(丢失)事件。
将.NET框架控件视为指南。它们都没有类似于IEventHackable的东西。