????在上一家公司創(chuàng)業(yè)初期积锅,我接觸的第一個項目是醫(yī)院的供應(yīng)室消毒包管理系統(tǒng),幾乎一人之力用了兩個多月的時間推溃,完成了基本的開發(fā)工作昂利。回想起來铁坎,當(dāng)時有個設(shè)計印象深刻页眯。趁著還有記憶,記錄下來厢呵,供大家一時之需窝撵。
當(dāng)時開發(fā)的時候,對于物資的管理襟铭,自然離不開條碼槍的角色碌奉。設(shè)計的是無線條碼槍短曾,讓工作人員可以自由的在作業(yè)現(xiàn)場走動。但是有個用戶體驗問題赐劣,就是一般情況下嫉拐,條碼槍掃描的時候,都需要將輸入焦點放到文本框之中魁兼,這個限制會造成極為不好的用戶體驗婉徘。此外,在流程設(shè)計的時候咐汞,實際上一系列操作動作盖呼,是使用掃描不同命令條碼后,實現(xiàn)的化撕。比如啟動某功能几晤,掃碼后,確定繼續(xù)下一個動作等等植阴,全程不用碰PC機蟹瘾。
所以問題的核心就在于是否可以接觸焦點必須放到文本框之中的限制。
此方法并不是原創(chuàng)掠手,但是原始代碼是對WinForm平臺進行開發(fā)的憾朴,被我修改為支持WPF平臺。并且原文的鏈接已經(jīng)失效喷鸽,所以這段代碼還是很有價值的伊脓。
現(xiàn)在放出幾個關(guān)鍵點的代碼,加以說明魁衙,全部代碼在最后放出鏈接:
1.掃描監(jiān)聽器BarcodeScannerListener
使用WindowInteropHelper獲取傳入窗體的句柄报腔,并且綁定ThreadFilterMessage事件,達到從而可以觸發(fā)ProcessRawInputMessage方法
/// <summary>
/// 將監(jiān)聽器附著到窗體上
/// </summary>
/// <param name="form">需要附著的窗體(WPF)</param>
public void Attach(Window form)
{
var helper = new WindowInteropHelper(form);
IntPtr hwnd = helper.Handle;
form.KeyDown += (sender, args) =>
{
if (_ControlHandled)
{
args.Handled = true;
_ControlHandled = false;
}
};
DoAttach(hwnd);
}
/// <summary>
/// 監(jiān)聽綁定
/// </summary>
/// <param name="hwnd">設(shè)備指針</param>
private void DoAttach(IntPtr hwnd)
{
this.keystrokeBuffer = new StringBuilder();
this.InitializeBarcodeScannerDeviceHandles();
this.interopHelper.HookRawInput(hwnd);
//this.HookHandleEvents(form);
//this.AssignHandle(ptr);
this.filter = new BarcodeScannerKeyDownMessageFilter();
ComponentDispatcher.ThreadFilterMessage -= ComponentDispatcher_ThreadFilterMessage;
ComponentDispatcher.ThreadFilterMessage += ComponentDispatcher_ThreadFilterMessage;
//Application.AddMessageFilter(this.filter);
}
ProcessRawInputMessage方法中剖淀,判斷傳入的字符串是否是掃碼槍設(shè)置的結(jié)束字符(掃碼的字符串是一個一個傳入的)纯蛾,如果不是,就加入到Buffer中纵隔,如果是翻诉,則觸發(fā)FireBarcodeScanned方法
/// <summary>
/// 處理WM_INPUT消息
/// </summary>
/// <param name="rawInputHeader">rawInputHeader的指針</param>
/// <returns>按鍵是否被處理</returns>
private bool ProcessRawInputMessage(IntPtr rawInputHeader)
{
BarcodeScannerDeviceInfo deviceInfo;
bool handled;
bool keystroke;
string localBuffer;
IntPtr rawInputDeviceHandle;
handled = false;
keystroke = false;
localBuffer = string.Empty;
rawInputDeviceHandle = IntPtr.Zero;
this.interopHelper.GetRawInputInfo(
rawInputHeader,
ref rawInputDeviceHandle,
ref keystroke,
ref localBuffer);
if (this.devices.TryGetValue(rawInputDeviceHandle, out deviceInfo) && keystroke)
{
handled = true;
// 這里判斷的是Tab按鍵,可以更換為其他按鍵
if (localBuffer.Length == 1 && (localBuffer[0] == 0x09 || localBuffer[0] == '\t'))
{
this.FireBarcodeScanned(deviceInfo);
}
else
{
this.keystrokeBuffer.Append(localBuffer);
}
}
return handled;
}
FireBarcodeScanned方法中捌刮,則會調(diào)用界面初始化時碰煌,綁定的事件,傳入掃碼的字符串
/// <summary>
/// 觸發(fā)掃碼事件
/// </summary>
/// <param name="deviceInfo">掃碼設(shè)備信息</param>
private void FireBarcodeScanned(BarcodeScannerDeviceInfo deviceInfo)
{
string barcode;
EventHandler handler;
barcode = this.keystrokeBuffer.ToString();
if (barcode.Length > 0)
{
handler = this.BarcodeScanned;
this.keystrokeBuffer = new StringBuilder();
if (handler != null)
{
handler(this, new BarcodeScannedEventArgs(barcode, deviceInfo));
}
}
}
2.頁面調(diào)用
這里我使用的MVVM模式绅作,所以在ViewModel層調(diào)用芦圾,但是只要能拿到View的對象,在那一層都沒有關(guān)系
BarcodeScannerListener = new BarcodeScannerListener();
BarcodeScannerListener.Attach((Window)GetView());
BarcodeScannerListener.BarcodeScanned += OnBarcodeScanned;
在傳入的事件中俄认,獲取Barcode屬性即可得到掃描的值
private void OnBarcodeScanned(object sender, EventArgs e)
{
string barcode = ((BarcodeScannedEventArgs)e).Barcode;
DoBarcodeScanned(barcode);
}
3.配置條碼槍的硬件ID
需要在windows設(shè)備管理器中个少,找到掃碼槍的設(shè)備ID洪乍,我這沒有圖上網(wǎng)找了一個
將這個設(shè)備ID保存在App.cofig中夜焦,可以是多個
<!--在上面先配置一下-->
<configSections>
<section name="barcodeScanner" type="Huitai.Cssd.Common.Util.Barcode.BarcodeScannerListenerConfigurationSection, Huitai.Cssd.Common" />
</configSections>
<barcodeScanner>
<hardwareIds>
<add id="HID#VID_05FE&PID_1010" />
</hardwareIds>
</barcodeScanner>
最后實現(xiàn)的效果還是十分不錯的壳澳,只要是系統(tǒng)處于前臺(不太確定處于后臺是否好用,有點記不住了)茫经,條碼槍隨意掃描巷波,一竄操作下來,根本不用動鍵盤或鼠標(biāo)卸伞,因為所有的靠鍵盤鼠標(biāo)觸發(fā)的功能抹镊,也都是使用特定條碼定義了,用戶體驗十分不錯瞪慧。可惜的是部念,最后這個系統(tǒng)因為商務(wù)原因弃酌,沒有上線,雖然完成度已經(jīng)很高了儡炼,但是也廢棄了妓湘。
最后,掃碼關(guān)鍵源碼的下載鏈接