C# WinForm + 条码扫描器输入,TextChanged 错误

3

更新:解决方案在结尾


我有一个Winform,label1将显示从SQL搜索返回的一些信息,使用通过txtBoxCatchScanner接收到的输入(MemberID)来扫描条形码。

情景是人们在通过接待处时在扫描仪下刷自己的MemberID卡,Winform会自动搜索该MemberID并返回他们的信息,包括例如“过期会员资格”等,这些信息会显示在接待员的桌面上的winForm的角落里。

我已经在第一次刷卡(例如第一个人)时成功运行了以下代码:

例如00888这个MemberID号码出现在文本框中,ADO.NET从SQL中提取数据并正常显示。

需要注意的一件事是,光标位于memberID的末尾:00888|

到目前为止都很好,然后:

当发生第二次刷卡(例如下一个人)时

他们的号码(比如00999)被放置在第一个号码的末尾,例如:0088800999,因此当TextChanged触发时,它会搜索0088800999而不是00999....

我已经尝试过:

txtBoxCatchScanner.Clear();

并且

txtBoxCatchScanner.Text = "";

在我的代码末尾添加“重新加载表单”以“刷新”文本框,但我猜它们会触发TextChanged事件。

如何重新聚焦或清除旧数字并将光标返回到txtBox的开头,以便在前一个滑动完成其工作后进行操作...

我是初学者,所以我确定下面的代码相当糟糕....

但如果有人有时间,请告诉我如何修复它以达到我想要的效果。

更新:

好的,在进行了大量实验后,我已经成功地让它1/2工作了,希望有更多经验的人能帮助我完成!:P

if (txtBoxCatchScanner.Text.Length == 5)
{
label1.Text = txtBoxCatchScanner.Text; // just a label for testing .. shows the memmber ID
txtBoxCatchScanner.Select(0, 5);
}

扫描第一张条形码,编号为00888,然后被突出显示。扫描第二个条形码,编号为00997……很好!覆盖(而不是追加)00888并完成其工作……扫描第二个条形码0011289…糟糕!!

问题:并非所有条形码都是5位数字!它们的长度是随机的!会员ID范围从2位数字(例如25)到10位数字,并且将来可能会增长......

编辑:我发现的问题是,条形码被读作单独的按键输入。我认为这就是下面答案1无法解决的原因,并且是大问题:

例如00675,来自扫描仪的输入(输出)为:

按下:Do 松开:Do 按下:Do 松开:Do 按下:D6 松开:D6 按下:D7 松开:D7 按下:D5 松开:D5 按下:返回 松开:返回

其他信息:条形码扫描仪为Opticon OPL6845 USB

谢谢

private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{             
    Member member = new Member();
    member.FirstName = "";
    member.LastName = "";            

    //Get BarCode
    //VALIDATE: Is a Number           
    double numTest = 0;
    if (Double.TryParse(txtBoxCatchScanner.Text, out numTest))
    {
        //IS A NUMBER
        member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);

        //SEARCH
        //Search Member by MemberID (barcode)
        List<Member> searchMembers = Search.SearchForMember(member);

        if (searchMembers.Count == 0)
        {
            lblAlert.Text = "No Member Found";
        }
        else
        {
            foreach (Member mem in searchMembers)
            {
                lblMemberStatus.Text = mem.MemberStatus;
                lblMemberName.Text = mem.FirstName + " " + mem.LastName;
                lblMemberID.Text = mem.MemberID.ToString();

                lblMessages.Text = mem.Notes;

                if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
                {
                    lblAlert.Visible = true;
                    lblAlert.Text = "!! OVERDUE !!";

                    //PLAY SIREN aLERT SOUND
                    //C:\\WORKTEMP\\siren.wav
                    SoundPlayer simpleSound = 
                        new SoundPlayer(@"C:\\WORKTEMP\\siren.wav");
                    simpleSound.Play();
                }
                else
                {
                    lblAlert.Visible = true;
                    lblAlert.Text = mem.MemberStatus;
                }
            }
        }
    }
    else
    {
        //IS NOT A NUMBER
        lblAlert.Text = "INVALID - NOT A NUMBER";                

        ////
        //lblMemberName.Text = "";
        //lblMemberID.Text = "";
        //lblMemberID.Text = "";
    }

解决方案:

系统不允许我在接下来的3个小时内回答自己的问题,因为我是一个新手只有1篇帖子,所以我会把答案放在这里:

首先感谢大家的帮助和耐心。

我终于找到了一个解决方法,还没有完全测试,因为现在已经是凌晨2点了,需要睡觉。

从我的更新中可以看出,我已经取得了成功,但遇到了MemberID变量长度的问题。现在我已经用以下代码解决了这个问题:

namespace SCAN_TESTING
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.KeyValue == (char)Keys.Return)
        {
            e.Handled = true;

            int barcodeLength = txtBoxCatchScanner.TextLength;

            txtBoxCatchScanner.Select(0, barcodeLength);

            //TEST
            label3.Text = barcodeLength.ToString();
            //TEST
            label2.Text = txtBoxCatchScanner.Text;

        }

    }

我会在明天将其添加到我的先前的“真实”代码中进行测试。但是目前为止它正在完全按照我的要求执行! =]
更新:已经测试过了,完全符合需求:
private void txtBoxCatchScanner_KeyUp(object sender, KeyEventArgs e)
{
   if (e.KeyValue == (char)Keys.Return)
      {
            e.Handled = true;

            int barcodeLength = txtBoxCatchScanner.TextLength;

            txtBoxCatchScanner.Select(0, barcodeLength);

           //
           //INSERT ORGINAL CODE HERE. No Changes were needed.
           //


      }//end of if e.KeyValue ...
}//end txtBoxCatchScanner_KeyUp

希望这能帮助未来的任何人!! :)
再次感谢提供的两个非常好的解决方案,我可以看到它们是如何工作的,并学到了很多。只是在我的情况下没有起作用——更可能是由于我自己或我的错误/不理解,或者扫描仪类型等原因。

2
@Soner Gönül:为什么你要增加缩进而不是去掉它呢? - default
文本框中的文本来自条形码扫描器,是这部分://是一个数字 member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text); ... 如果有帮助 - user1994097
2
@Default 我已经去掉了缩进 :-) - Uwe Keim
1
@UweKeim,谢谢! :) 看起来好多了。 - default
@RhysW:是的,如果扫描仪被配置为USB键盘模式,那么大多数简单的条码扫描仪默认就是这样。 - Thorsten Dittmar
显示剩余16条评论
3个回答

3
我不太确定实际问题是什么。
txtBoxCatchScanner.Clear();
txtBoxCatchScanner.Text = "";

两种方法都会触发“Changed”事件。但是它们也会清空框中的内容。所以这应该是您想要做的。

您可以在开始时检查框是否为空,并在其为空时返回。例如:

if(txtBoxCatchScanner.Text == "" |txtBoxCatchScanner.Text == string.Empty)
return;

如果盒子是空的,就不会发生任何其他事情。
如果我误解了您的问题,请具体说明,我会尽力帮助。
敬礼
编辑:
如果您的函数看起来像这样,它应该可以工作:
    private void txtBoxCatchScanner_TextChanged(object sender, EventArgs e)
{             
Member member = new Member();
member.FirstName = "";
member.LastName = "";            

if(txtBoxCatchScanner.Text == "" | txtBoxCatchScanner.Text == string.Empty)
return;    // Leave function if the box is empty

//Get BarCode
//VALIDATE: Is a Number           
int numTest = 0;
if (int.TryParse(txtBoxCatchScanner.Text, out numTest))
{
    //IS A NUMBER
    //member.MemberID = Convert.ToInt32(txtBoxCatchScanner.Text);
    member.MemberID = numTest; // you already converted to a number...
    //SEARCH
    //Search Member by MemberID (barcode)
    List<Member> searchMembers = Search.SearchForMember(member);

    if (searchMembers.Count == 0)
    {
        lblAlert.Text = "No Member Found";
    }
    else
    {
        foreach (Member mem in searchMembers)
        {
            lblMemberStatus.Text = mem.MemberStatus;
            lblMemberName.Text = mem.FirstName + " " + mem.LastName;
            lblMemberID.Text = mem.MemberID.ToString();

            lblMessages.Text = mem.Notes;

            if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
            {
                lblAlert.Visible = true;
                lblAlert.Text = "!! OVERDUE !!";

                //PLAY SIREN aLERT SOUND
                //C:\\WORKTEMP\\siren.wav
                SoundPlayer simpleSound = 
                    new SoundPlayer(@"C:\\WORKTEMP\\siren.wav");
                simpleSound.Play();
            }
            else
            {
                lblAlert.Visible = true;
                lblAlert.Text = mem.MemberStatus;
            }
        }
    }
}
else
{
    //IS NOT A NUMBER
    lblAlert.Text = "INVALID - NOT A NUMBER";                

    ////
    //lblMemberName.Text = "";
    //lblMemberID.Text = "";
    //lblMemberID.Text = "";
}
txtBoxCatchScanner.Clear();
}

问题是,如果我执行txtBoxCatchScanner.Clear()/等操作,它会触发TextChanged事件,然后触发搜索成员ID为""的操作。显然,这里的""代表一个空格,而不是一个数字,也没有ID为[空格]的成员,因此会得到"无效数字"和"未找到成员"的响应。 - user1994097
@User1994097 是的,因为清除它是一个文本更改事件,但在您的代码中的某个地方,您必须将该文本框设置为来自扫描仪的数字,在代码的这一点上存在错误,即您不是用新数字覆盖旧数字,而是将其附加,这会给您带来长数字,我可以为您解决此问题,但是为此您需要展示设置文本框文本为数字的代码。 - user1645826
你的代码中一定有设置文本框显示扫描仪数字的部分 - 不是这样的,条形码扫描器的工作方式是:扫描条形码并将数字输出到任何处于焦点状态的地方...打开一个 .txt 文件并将光标放在那里,它会将数字输出到该文件...打开一个 .xls 文件并将光标放在单元格中...它会将数字输出到该单元格...或者在这种情况下...打开一个带有光标在文本框中(“在焦点中”)的窗体,它会将数字输出到该文本框中,没有代码...不像单击事件... - user1994097
我以为你知道条形码扫描器的工作原理,但我应该更清楚地解释,抱歉。不幸的是,这个解决方案不起作用。 - user1994097
1
很抱歉要这么说,但你真的不应该使用“TextChanged”事件!这是一个坏主意,因为它在你编辑文本时被调用 - 即使用户手动输入文本也是如此。这意味着每添加一个字符,无论是通过键盘还是扫描仪,都会触发一个事件,导致成员ID的验证。不要这样做!我不想过度宣传我的方法,但它更加简洁... - Thorsten Dittmar
显示剩余7条评论

3
您使用的条码扫描器似乎作为HID进行功能控制,即模拟键盘。在我所知道的每个简单的条码扫描器上(而且我每天都在使用),都有指定扫描条形码后缀的选项。将后缀更改为CRLF,并在表单中添加一个默认按钮。以CRLF结尾的条码扫描将自动“按下按钮”。
将执行检查的代码从TextChanged事件移动到按钮Click事件的事件处理程序中,并删除TextChanged事件处理程序。然后,当点击按钮时,还要清除文本框并将焦点设置回文本框。
现在,您应该可以顺利运行了。
您可以轻松检查条码扫描器是否已配置正确的后缀:打开记事本并扫描一些条形码。如果它们全部出现在单独的行上,则一切正常。否则,您需要从扫描仪手册中扫描一些配置条形码。
总之,这应该是按钮Click事件的代码:
private void btnCheckMember_Click(object sender, EventArgs e)
{             
    Member member = new Member();
    member.FirstName = "";
    member.LastName = "";            

    string memberText = txtBoxCatchScanner.Text.Trim();
    txtBoxCatchScanner.Text = String.Empty;

    int numTest = 0;
    if (String.IsNullOrEmpty(memberText) ||!Int32.TryParse(memberText, out numTest))
    {
        //IS NOT A NUMBER
        lblAlert.Text = "INVALID - NOT A NUMBER";                
        return;
    }

    member.MemberID = numTest;
    List<Member> searchMembers = Search.SearchForMember(member);

    if (searchMembers.Count == 0)
    {
        lblAlert.Text = "No Member Found";
    }
    else
    {
        foreach (Member mem in searchMembers)
        {
            lblMemberStatus.Text = mem.MemberStatus;
            lblMemberName.Text = mem.FirstName + " " + mem.LastName;
            lblMemberID.Text = mem.MemberID.ToString();

            lblMessages.Text = mem.Notes;

            if (mem.MemberStatus == "OVERDUE") // OR .. OR .. OR ...
            {
                lblAlert.Visible = true;
                lblAlert.Text = "!! OVERDUE !!";

            SoundPlayer simpleSound = new SoundPlayer(@"C:\\WORKTEMP\\siren.wav");
            simpleSound.Play();
        }
        else
        {
            lblAlert.Visible = true;
            lblAlert.Text = mem.MemberStatus;
        }
    }
}

此解决方案避免了以下问题:
  1. 每次从文本框的内容中添加/删除字符时触发事件(这也是扫描条形码时的情况:它们被逐个添加,就像它们是通过键盘输入的一样)
  2. 由于1.,每输入一个字符都会执行一次成员检查的问题
  3. 由于2.,如果数据库中有成员XY并且检查在找到XY后停止,则永远不会找到成员XYZ
  4. 由于3.,文本框被清除并只输入了Z,因此也无法找到成员XY,只能找到成员Z

谢谢,我会尝试这个答案1并让你们知道。非常感谢。 - user1994097
没问题。请确保使用记事本(甚至是Visual Studio编辑器)将每个扫描放在单独的一行上 - 否则按钮将无法“按下”,您需要先配置后缀。 - Thorsten Dittmar
似乎您已经获取了 CRLF。为确保:关闭所有程序,启动记事本并多次扫描。条形码是否出现在单独的行上?或者:向表单添加一个按钮,分配它的 Click 处理程序以显示一个 MessageBox,将表单的 AcceptButton 属性设置为新按钮,然后运行和扫描 - 您是否看到了 MessageBox?如果是这样,一切都已经很好了。 - Thorsten Dittmar
似乎这个扫描仪不能做后缀更改。http://old.opticon.com/Cabled--Laser-Barcode-Scanner--01028910382002.aspx 明天会调查一下。晚安,谢谢。 - user1994097
问题已解决。感谢您的帮助!我会发布解决方案。 - user1994097
显示剩余4条评论

1

在下一个textChange事件中清除textBox的最佳方法。

插入这行代码

txtBoxCatchScanner.SelectAll();

在TextChange函数的末尾...这将选择文本,以便在下一个事件中可以轻松替换它。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接