使用条码扫描器的WPF应用程序中的多线程问题
本文关键字:多线程 问题 应用程序 WPF 条码扫描器 | 更新日期: 2023-09-27 18:13:25
我使用的是MVVM风格的架构,整个应用程序运行良好。但我在应用程序中引入了一个扫描仪,现在有许多多线程问题。以下只是一些伪代码,但基本上是我需要它工作的方式:
View.xaml
<DataGrid ItemsSource="{Binding MyList}"/>
View.xaml.cs
class View : UserControl
{
public View()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
ViewModel.cs
class ViewModel
{
private Scanner scanner;//this is my scanner, duh
public ViewModel()
{
scanner = new Scanner();
scanner.ScanEvent += ScanEvent;
//all this does is when the scanner scans something
//then it will trigger an event looking for method ScanEvent()
}
public ObservableCollection<string> MyList{ get; set; }
public void ScanEvent()
{
string strBarcode = scanner.strBarcode;
MyList.Insert(0, strBarcode);//this is where the error is thrown
}
}
抛出的错误是This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
。当我将扫描仪设置为我的一个对象时,扫描仪工作正常,所以我不明白为什么我不能用这个ObservableCollection
做同样的事情?下面是我的扫描器类中处理事件的一个片段:
Scanner.cs
internal class Scanner
{
public delegate void EventHandler();
public event EventHandler ScanEvent = delegate { };
public Scanner()
{
m_pCoreScanner.BarcodeEvent += new _ICoreScannerEvents_BarcodeEventEventHandler(OnBarcodeEvent);
RegisterForEvents();
}
public void OnBarcodeEvent(short eventType, ref string scanData)
{
strBarcode = GetBarcodeFromXml(scanData);
ScanEvent();
}
//this class is huge, so I only included pertinent code
}
正如异常消息所说,你必须在UI(或Dispatcher)线程中更新ObservableCollection,因为UI元素的属性(DataGrid.ItemsSource
)被绑定到集合。
试试这个:
public void ScanEvent()
{
string strBarcode = scanner.strBarcode;
Application.Current.Dispatcher.Invoke(
new Action(() => MyList.Insert(0, strBarcode)));
}
如果您想避免使用Dispatcher。当想要返回UI线程时,到处调用-我同意这是丑陋的,并且对测试没有很大帮助。你可以尝试使用响应式扩展(Rx . net)。
使用Rx,你可以用"推"的方式来处理事件,而不是标准的。net事件方式(拉模型)。这将允许你在事件数据上编写LINQ风格的查询,重要的是,在你的情况下,将调度处理回dispatcher (UI)线程。
下面是重写的代码,使用Rx代替标准的。net事件模型:
。. Net框架版本= 4.0 (WPF)Rx版本= 2.0.21103.1
nuGet上有新版本的Rx框架可用,如果你打算将它们与WPF一起使用,你还需要包括Rx-WPF。
internal class Scanner
{
public IObservable<EventArgs> ScanEvent
{
get
{
return Observable.FromEventPattern<EventHandler, EventArgs>(
h => m_pCoreScanner.BarcodeEvent += h, h => m_pCoreScanner.BarcodeEvent -= h)
.Select(x => x.EventArgs);
}
}
}
class ViewModel : IDisposable
{
private Scanner scanner;
private IDisposable _disposable;
public ViewModel()
{
scanner = new Scanner();
MyList = new ObservableCollection<string>();
_disposable = scanner.ScanEvent
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(x =>
{
string strBarcode = scanner.strBarcode;
MyList.Insert(0, strBarcode);
});
}
public void Dispose()
{
_disposable.Dispose();
}
public ObservableCollection<string> MyList { get; set; }
}
一个开始学习Rx的好地方是这个免费的在线电子书- http://www.introtorx.com/
如果您使用MvvmLight这样的框架,您可以利用消息机制。在VM中注册一个处理程序,然后从扫描器库发送消息
http://wbsimms.com/mvvm-light-toolkit-messaging-example/这些消息通过默认单例跨程序集工作,但这取决于您的扫描仪库是否可自定义。