我想对莫尔斯电码闪烁灯进行一系列定时事件。指示灯闪烁时,应该可以使用该程序。
因此,开始时会有一个长时间的停顿,然后它将开始闪烁长而短的信号,中间停顿一会儿,然后重新开始。
示例序列
我尝试了这段代码,但它只会冻结程序
private void Morse()
{
System.Timers.Timer MorseCode = new System.Timers.Timer(3000);
MorseCode.Elapsed += new ElapsedEventHandler(long);
MorseCode.Elapsed += new ElapsedEventHandler(short);
MorseCode.Elapsed += new ElapsedEventHandler(long);
MorseCode.Elapsed += new ElapsedEventHandler(short);
void short(object sender, ElapsedEventArgs e)
{
MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
MorseCode.Interval = 400;
MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
MorseCode.Interval = 500;
}
void long(object sender, ElapsedEventArgs e)
{
MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
MorseCode.Interval = 1200;
MorseCode.Elapsed += new ElapsedEventHandler(ColorChange);
MorseCode.Interval = 500;
}
void ColorChange(object sender, ElapsedEventArgs e)
{
if(BlinkLight.BackColor == Color.Gray)
{
BlinkLight.BackColor = Color.DodgerBlue;
}
else
{
BlinkLight.BackColor = Color.Gray;
}
}
}
那么我该如何为闪烁的灯光设置不同的时序?
答案 0 :(得分:0)
为此使用Microsoft的Reactive Framework-NuGet“ System.Reactive.Windows.Forms”。
然后您可以执行以下操作:
int[] timings = new [] { 3000, 1200, 500, 400, 500, 1200, 500, 400 };
IObservable<System.Drawing.Color> sequence =
Observable
.Generate(
0,
x => x < timings.Length,
x => x + 1,
x => x % 2 == 1 ? System.Drawing.Color.DodgerBlue : System.Drawing.Color.Gray,
x => TimeSpan.FromMilliseconds(timings[x]));
IDisposable subscription =
sequence
.Repeat()
.ObserveOn(BlinkLight)
.Subscribe(color => BlinkLight.BackColor = color);
答案 1 :(得分:0)
您可以为此使用任务并行库,它包含在.NET 4及更高版本中。这将产生清晰的可读代码,如下所示:
private void Morse()
{
BlinkShort().ContinueWith( //
BlinkShort).ContinueWith( // S
BlinkShort).ContinueWith( //
BlinkLong).ContinueWith( //
BlinkLong).ContinueWith( // O
BlinkLong).ContinueWith( //
BlinkShort).ContinueWith( //
BlinkShort).ContinueWith( // S
BlinkShort); //
}
辅助方法的示例实现:
private Task BlinkShort(Task previousTask = null)
{
var action = new Action(() =>
{
SetColorSafe(true);
Task.Delay(400).Wait();
SetColorSafe(false);
Task.Delay(500).Wait();
});
var t = Task.Run(action);
if (previousTask != null) // already threaded
{
t.Wait();
}
return t;
}
private Task BlinkLong(Task previousTask = null)
{
var action = new Action(() =>
{
SetColorSafe(true);
Task.Delay(1200).Wait();
SetColorSafe(false);
Task.Delay(500).Wait();
});
var t = Task.Run(action);
if (previousTask != null) // already threaded
{
t.Wait();
}
return t;
}
private void SetColorSafe(bool on)
{
if (InvokeRequired)
{
Invoke(new Action(() => {
SetColorSafe(on);
}));
return;
}
if (on)
{
BackColor = Color.DodgerBlue;
}
else
{
BackColor = Color.Gray;
}
}
答案 2 :(得分:0)
我喜欢Enigmativity's solution。如果您知道System.Reactive
,那就是个选择。
这是一个使用异步任务的简单解决方案。
我正在传递给异步方法:
-一个List<Tuple<int, int>>
,代表信号的间隔和持续时间
-将作为视觉输出的Control
引用
-CancellationToken
,用于发信号通知任务何时终止。
可以取消任务,然后以相同的顺序或新的顺序重新开始。
如果未取消,任务将无限期执行,播放当前序列。
在这里,我正在使用一个按钮来启动任务。我可以是其他人。
请注意,我已经稍微修改了顺序和时间。每个序列迭代之间的暂停都在序列的末尾,因此它会立即启动信号,然后在每个序列执行后将其暂停。
发出取消请求后,任务将在取消之前完成序列:
if (token.IsCancellationRequested) return;
仅在序列完成后才检查,以免弄乱时间。但这可以修改为在每次长时间停顿后检查取消。
CancellationTokenSource source;
CancellationToken token;
private void button1_Click(object sender, EventArgs e)
{
if (source != null)
{
source.Cancel();
source.Dispose();
source = null;
return;
}
source = new CancellationTokenSource();
token = source.Token;
List<Tuple<int, int>> MorseCodeSequence = new List<Tuple<int, int>>()
{
new Tuple<int, int>(1200, 200),
new Tuple<int, int>(400, 200),
new Tuple<int, int>(1200, 200),
new Tuple<int, int>(400, 2000)
};
Task.Run(()=> MorseSequence(MorseCodeSequence, this.btnMorse, token));
}
public async Task MorseSequence(List<Tuple<int, int>> MorseSequence, Control MorseCodeOutputObject, CancellationToken token)
{
while (true)
{
foreach (Tuple<int, int> MorseTiming in MorseSequence)
{
MorseCodeOutputObject.BeginInvoke(new MethodInvoker(() =>
{ MorseCodeOutputObject.BackColor = Color.Cyan; }));
await Task.Delay(MorseTiming.Item1);
MorseCodeOutputObject.BeginInvoke(new MethodInvoker(() =>
{ MorseCodeOutputObject.BackColor = Color.Gray; }));
await Task.Delay(MorseTiming.Item2);
}
if (token.IsCancellationRequested) return;
};
}
SOS
序列
List<Tuple<int, int>> SOSMorseSequence = new List<Tuple<int, int>>()
{
new Tuple<int, int>(400, 200),
new Tuple<int, int>(400, 200),
new Tuple<int, int>(400, 300),
new Tuple<int, int>(1200, 200),
new Tuple<int, int>(1200, 200),
new Tuple<int, int>(1200, 300),
new Tuple<int, int>(400, 200),
new Tuple<int, int>(400, 200),
new Tuple<int, int>(400, 2000),
};