有人会出现,可能会给出比这更优雅的答案。但我发现这个具有挑战性。
首先,这个例子没有展示如何为表单上的键做这件事。那里有足够的额外复杂性,需要先尝试自己,或者问另一个问题。在这里需要一个完整的应用程序来回答您问题的所有方面。可以这么说:
- 您可以将 KeyEventArgs 转换为可在此框架中使用的 observable
- 您可以决定使用SuppressKeyPress
KeyEventArgs
将其抑制到条形码流中
- 您可以决定不抑制
KeyEventArgs
非条形码流中的任何内容
目前的解决方案涉及定义一个函数,该函数采用 aIObservable<char>
并将其转换为 aGroupedObservable
标记(用 a bool
)底层字符是否在“条形码”流中(真)或不(假):
public IObservable<IGroupedObservable<bool, IObservable<char>>> GroupBySurroundingChars(IObservable<char> source, char ends, TimeSpan within)
{
var result =
source.Buffer(() =>
source.Select(c => {
if (c == ends) return source.Where(x => x == ends).Amb(Observable.Timer(within).Select(_ => default(char)));
else return Observable.Return(default(char));
}).Concat())
.GroupBy(buffer => buffer.Count > 2 && buffer[0] == ends && buffer.Last() == ends, buffer => buffer.ToObservable());
return result;
}
这个函数的作用是:
- 用每个字符开始一个缓冲区
- 如果该字符不是逗号,则立即返回缓冲区
- 如果该字符是逗号,则保持缓冲区打开,直到找到另一个逗号或 250 毫秒过去
- 检查缓冲区是否在两端包含逗号(标记为条形码)或不包含(标记为无条形码)
然后是一个完整的用法示例:
var keys1 = "xxx,1234567,xxx,1,xxx".ToCharArray().ToObservable(Scheduler.ThreadPool).Do(_ => Thread.Sleep(100)).Publish().RefCount();
var keys2 = "xxx,1234567,xxx,1,xxx".ToCharArray().ToObservable(Scheduler.ThreadPool).Do(_ => Thread.Sleep(10)).Publish().RefCount();
var result = GroupBySurroundingChars(keys1, ',', TimeSpan.FromMilliseconds(250));
var barcodes = result.Where(x => x.Key);
var others = result.Where(x => !x.Key);
barcodes.Subscribe(groups => groups.Subscribe(x => x.ToList().Dump()));
如果使用keys1
,按键速度太慢,无法找到第一个条形码,但它会找到第二个。如果您使用keys2
,按键速度足以找到两个条形码。
在任何一种情况下,others
流都包含最终未标记为包含条形码的所有键。该barcodes
流可以被视为一个字符一个字符的流,或者List
像我上面所做的那样与每组条形码一起转换为一个。