WPF扫码后自动重置/刷新TextBox的实现方法
实现WPF扫码枪连续扫码无需手动清空TextBox的方案
问题背景
我正在开发一款简易WPF程序,用户使用USB扫码枪扫描条码后,程序会将数据直接发送至云ERP。目前程序可正常运行,但用户扫码后需手动点击TextBox并清除数据才能再次扫码,希望实现打开软件后可连续扫码,无需手动清空TextBox。
现有代码
MainWindow.xaml
<Window x:Class="ProductionScanner.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModel="clr-namespace:ProductionScanner.MVVM.ViewModel" xmlns:local="clr-namespace:ProductionScanner" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Background="#181735" > <Window.DataContext> <viewModel:ReceiptViewModel /> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="25" /> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid Background="#0F0F2D" Grid.ColumnSpan="2"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <TextBlock Text="Foods" Foreground="White" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Left" /> <TextBlock Text="Records" Foreground="White" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Center" /> </Grid> <StackPanel FocusManager.FocusedElement="{Binding ElementName=txtIniFocus}"> <TextBox x:Name="txtIniFocus" Margin="6" Text="{Binding Barcode, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="150" Grid.Row="1" TextChanged="TextBox_TextChanged"> <TextBox.InputBindings> <KeyBinding Key="Enter" Command="{Binding ReceiptCommand}" /> </TextBox.InputBindings> </TextBox> </StackPanel> </Grid>
ReceiptViewModel.cs
using ProductionScanner.Cores; using ProductionScanner.MVVM.Model; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Windows; using System.Windows.Controls.Primitives; namespace ProductionScanner.MVVM.ViewModel { public class ReceiptViewModel: ObservableObject { private string _barcode; public string Barcode { get { return _barcode; } set { _barcode = value; OnPropertyChanged(); } } public RelayCommand ReceiptCommand { get; set; } public ReceiptViewModel() { ReceiptCommand = new RelayCommand(x => { receiptInventory(); }); } private void receiptInventory() { if (Barcode.Length == 12) { var inventoryIDFrom = Barcode.Substring(0, 6); var kgIntFrom = Barcode.Substring(6); var kgDecimalFrom = kgIntFrom.Substring(0,kgIntFrom.Length-4) + "." + kgIntFrom.Substring(kgIntFrom.Length - 4, 3); ERPRestService _erpRestService = new ERPRestService(); ReceiptItems receiptItems = new ReceiptItems(); receiptItems.InventoryID = inventoryIDFrom; receiptItems.Qty = Convert.ToDecimal(kgDecimalFrom); receiptItems.WarehouseID = "WH001"; receiptItems.LocationID = "L001"; receiptItems.LotSerialNbr = ""; receiptItems.ExpirationDate = DateTime.Now; try { var jsonObj1 = new { Description = new { value = "Receipt" }, Hold = new { value = false }, Details = new[] { new { InventoryID = new { value = receiptItems.InventoryID }, Qty = new { value = receiptItems.Qty }, WarehouseID = new { value = receiptItems.WarehouseID }, Location = new { value = receiptItems.LocationID } } } }; string entityAsString = JsonConvert.SerializeObject(jsonObj1); //string parameters1 = "$expand=Details"; var receipt = _erpRestService.Put("InventoryReceipt", null, entityAsString); string refRelease = JObject.Parse(receipt)["ReferenceNbr"]["value"].ToString(); var release = new { entity = new { ReferenceNbr = new { value = refRelease } } }; string jsonRelease = JsonConvert.SerializeObject(release); jsonRelease = _erpRestService.Post("InventoryReceipt", "ReleaseInventoryReceipt", jsonRelease); MessageBox.Show("Your AR Confirm has completed.", "Confirm", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { throw (ex); } finally { _erpRestService.Dispose(); } } } }
解决方案
要实现连续扫码,核心是完成扫码处理后自动清空绑定的条码字段,并确保TextBox始终保持焦点。
方法1:命令执行完成后自动清空条码
修改receiptInventory方法的finally块,添加清空Barcode字段的代码,绑定的TextBox会自动同步清空,且初始设置的焦点会保留,下次扫码可直接输入:
finally { _erpRestService.Dispose(); // 清空条码绑定字段,TextBox会自动同步清空 Barcode = string.Empty; }
这种方式适配绝大多数扫码枪(扫码枪通常会自动追加回车触发ReceiptCommand),逻辑简洁且不易出错。
方法2:通过TextChanged事件自动触发处理(适配无回车的扫码场景)
如果扫码枪不会自动追加回车,可通过TextBox的TextChanged事件,在条码长度符合要求时自动触发命令并清空:
在MainWindow.xaml.cs中添加事件处理代码:
private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { var textBox = sender as TextBox; if (textBox == null) return; // 当条码长度达到设定的12位时,自动触发处理 if (textBox.Text.Length == 12) { var viewModel = DataContext as ReceiptViewModel; viewModel?.ReceiptCommand.Execute(null); // 延迟清空确保命令处理完成 Dispatcher.InvokeAsync(() => textBox.Text = string.Empty); } }
额外注意事项
- 若存在其他控件抢占焦点的情况,可在清空条码后主动调用
txtIniFocus.Focus()确保焦点回到TextBox。 - 避免重复触发:使用方法1时,回车触发命令后再清空条码,不会因TextChanged事件重复执行处理逻辑。
内容的提问来源于stack exchange,提问作者David Lightman
相关产品推荐
相关产品推荐

