0

「、」のプレフィックスとサフィックスを追加し、それ以外はキーボードのように機能するようにバーコード リーダーをプログラムしました。バーコードがスキャンされたときに開く Windows フォームがあります。

Reactive Extensions は、一連の KeyDown コードを記述するよりも、この種の作業に最適なようです。私がしたいこと:

  • コンマが押されたら、キーを押したままにします (画面上のコントロールでキーを処理させないでください)。
  • 別のコンマが押されるか、250ms が経過するまで、すべてのキーを収集します。
  • 250 ミリ秒以内にコンマが押されない場合は、アクティブなコントロールにキーを押し戻します。
  • カンマが押された場合、バーコードからスキャンされた文字列値に対して処理を行います。

System.Reactive を使用して、バーコード スキャナーのプレフィックスとサフィックスを照合するときにキーの押下を保持し、サフィックスが一致する場合は処理しますが、サフィックスが制限時間内に一致しない場合はキーの押下を通常どおり処理するにはどうすればよいですか?

4

2 に答える 2

1

誰かがやって来て、おそらくこれよりもエレガントな答えを出すでしょう. しかし、私はこれが難しいと感じました。

まず最初に、この例ではフォームのキーに対してそれを行う方法を示していません。そこには、最初に自分で試したり、別の質問をしたりするのに十分な追加の複雑さがあります。ここであなたの質問のすべての側面に答えるには、完全なアプリケーションが必要です. 次のように言えば十分です。

  1. KeyEventArgs を、このフレームワークで使用できるオブザーバブルに変えることができます
  2. SuppressKeyPressKeyEventArgsを使用して、バーコード ストリームにすることを抑制することができます。
  3. KeyEventArgs非バーコード ストリームでは抑制しないことを決定できます。

IObservable<char>現状の解決策には、 を取り、それを に変換する関数を定義することが含まれます。これは、基になる char が「バーコード」ストリーム内にあるか (true)、そうでないか (false)GroupedObservableを ( で) マークします。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;
}

この関数が行っていることは次のとおりです。

  1. すべての文字でバッファを開始する
  2. その文字がコンマでない場合は、すぐにバッファを返します
  3. その文字がコンマだった場合、別のコンマが見つかるか、250ms が経過するまでバッファを開いたままにします
  4. バッファの両端にコンマが含まれているか (バーコードとしてマーク)、含まれていないか (バーコードなしとしてマーク) を確認します。

そして、完全な使用例:

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と、キーを押すのが遅すぎて最初のバーコードが見つかりませんが、2 番目のバーコードは見つかります。を使用するkeys2と、キーを押すだけで両方のバーコードを見つけることができます。

いずれの場合も、othersストリームには、最終的にバーコードを含むとマークされなかったすべてのキーが含まれます。ストリームは、文字ストリームごとに文字として取得することも、上記で行ったようにバーコードの各セットで にbarcodes変換することもできます。List

于 2012-07-04T06:05:19.910 に答える
1

これを少しずつ分解していきましょう。

まず、Observable としてキーを押す必要があります。

        var keys =
        Observable.FromEventPattern<KeyEventHandler, KeyEventArgs>(
                a => this.KeyDown += a,
                a => this.KeyDown -= a
            ).Select(ea => ea.EventArgs)
            .Publish();

        var unsubscription = keys.Connect();

キープレスの受信に基づいて、バッファリングを描写する条件があります。

        Func<KeyEventArgs, bool> isDelimiter =
            k => k.KeyCode == Keys.Oemcomma;

これで、バッファ条件が満たされるたびに通知を受け取ることができますkeys.Where(isDelimiter)

区切り文字が検出された場合、または入力が与えられないまでしばらく時間が経過した場合は、バッファを閉じる必要があります。

Observable.Amb(keys.Where(isDelimiter), keys.Throttle(TimeSpan.FromMilliseconds(2000))

これらを組み合わせて、これらの条件で発生する文字のウィンドウを作成できます。

        var windows = 
            keys.Window(keys.Where(isDelimiter),
                        first => Observable.Amb(
                                    keys.Where(isDelimiter), 
                                    keys.Throttle(TimeSpan.FromMilliseconds(2000)
                                )
                                .Where(_ => isDelimiter(first))));

あとは、ウィンドウが閉じるまでバッファリングを続け、バッファリング中に残りのコントロールがキーを受信しないようにブロックするだけです。

        windows
            .SelectMany(window => window
                                        .Do(ka => ka.SuppressKeyPress = true)
                                        .Buffer(() => Observable.Never<KeyEventArgs>())
                                        )
            .Subscribe(buf => Trace.WriteLine(new string(buf.Select(ka => (char)ka.KeyValue).ToArray())));

SelectManyバッファリングされたキープレスの最終ストリームを取得し、最終的にプログラムロジックを配置できます。ここでは、単純にリストを文字列として Trace に出力しました。

于 2012-07-04T16:04:34.407 に答える