帮助System.Reflection.TargetInvocationException [英] Help with System.Reflection.TargetInvocationException

查看:62
本文介绍了帮助System.Reflection.TargetInvocationException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

需要帮助!无法弄清楚这里发生了什么。我有一个保存对象的异步 bindingList 。在工作线程上创建此异步 bindingList ,并在工作线程上添加,更新和删除对象。在主UI线程上,我的 bindingList 绑定到 bindingSource ,它绑定到 dataGridView



我一直得到System.Reflection.TargetInvocationException并且索引越界异常。

可以有人请帮帮我吗?



这是我得到的最后一个例外:

Need help! Can't figure out what's going on here. I have a asynchronous bindingList that holds objects. This asynchronous bindingList is created on a worker thread and objects are added, updated and removed on the worker thread. On the Main UI thread my bindingList is bound to a bindingSource that's bound to a dataGridView.

I keep getting "System.Reflection.TargetInvocationException" and index out of bounds exception.
Can someone please help me out here?

Here's the last exception I got:

System.Reflection.TargetInvocationException was unhandled
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
       at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
       at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
       at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
       at System.Delegate.DynamicInvokeImpl(Object[] args)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
       at System.Threading.ExecutionContext.runTryCode(Object userData)
       at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
       at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.DataGridView.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(Form mainForm)
       at StrategyViewer.Program.Main() in C:\C Sharp Applications\StrategyViewer\StrategyViewer\Program.cs:line 18
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.IndexOutOfRangeException
       Message=Position is either less than 0 or greater than the number of items in the data source.
       Source=System.Windows.Forms
       StackTrace:
            at System.Windows.Forms.CurrencyManager.ChangeRecordState(Int32 newPosition, Boolean validating, Boolean endCurrentEdit, Boolean firePositionChange, Boolean pullData)
            at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
            at System.Windows.Forms.BindingSource.OnListChanged(ListChangedEventArgs e)
            at System.Windows.Forms.BindingSource.InnerList_ListChanged(Object sender, ListChangedEventArgs e)
            at System.ComponentModel.BindingList`1.OnListChanged(ListChangedEventArgs e)
       InnerException: 



我得到的印象由于我的 bindingList 操作,我的工作线程抛出了这个异常。


I getting the impression that this exception is being throw on my worker thread because of my bindingList manipulations.

推荐答案

你真的不应该修改后台线程上的数据绑定对象,使其更新th e UI。如果没有得到TargetInvocationException,您将收到有关跨线程调用的警告。任何在BindingList中添加,修改或删除项目的尝试都会触发UI从后台线程更新自身,这是禁止的。
You really should not modify a data bound object on a background thread in such a way that it updates the UI. If you don't get TargetInvocationException, you will get warnings about cross-thread calls. Any attempt to Add, modify or Remove items in the BindingList is going to trigger the UI to update itself from a background thread, and this is a no-no.


线程安全意味着多个线程可以同时使用它,而不需要你做任何特殊的事情,比如创建锁或关键部分。因此,多个线程可以同时添加到列表中而不会导致问题。虽然您的集合可能是线程安全的,但控件却不是。如果控件是数据绑定的,则修改数据会立即反映在UI中。使用多个线程时,数据绑定很好但很难。



BackgroundWorker是使用修改UI数据的后台线程的首选方法。您在DoWork中完成工作,并在RunWorkerCompleted中更新集合/对象/ UI。可以从常规线程获得你想要的东西,这里是你如何做到的:



Control类有一个名为InvokeRequired的属性。这是一个布尔值,它从UI线程始终是错误的,并且从后台线程始终是真的。这是您可以从后台线程访问的少数几个Control属性之一。如果你想从一个线程更新Label的文本,你会有这样的函数:



Thread-safe means that multiple threads can work with it at the same time without requiring you to do anything special, like creating locks or critical sections. So multiple threads could add to a list at the same time and not cause problems. While your collection may be thread safe, controls are not. If controls are data-bound, then modifying the data is reflected in the UI instantly. Data binding is nice but difficult when working with multiple threads.

BackgroundWorker is the preferred way to work with background threads that modify UI data. You do your work in DoWork, and update your collection / object / UI in RunWorkerCompleted. It is possible to get what you want from a regular thread though, here's how you do it:

The Control class has a property called InvokeRequired. This is a boolean, it will always be false from the UI thread and it will always be true from a background thread. This is one of the few properties of Control that you can access from a background thread. If you wanted to update a Label's Text from a thread, you would have a function like this:

Delegate void UpdateTextCallback(String text);

void UpdateLabelText(String text)
{
    // if invoke required, tell label to execute this on its thread
    if (Label1.InvokeRequired)
    {
        UpdateTextCallback callback = new UpdateTextCallback(UpdateLabelText);
        Label1.Invoke(callback, new Object() { text });
    }
    else // we are on the correct thread, set label text
    {
        Label1.Text = text;
    }
}





在你的情况下,你可以检查你的DataGridView.InvokeRequired,如果有的话,添加一个项目使用上面类似的模式到集合。我强烈建议使用BackgroundWorker,它设置为做你想要做的事情。



In your case, you can check your DataGridView.InvokeRequired and if so add an item to the collection using a similar pattern above. I strongly recommend using BackgroundWorker though, it is setup to do the kind of things that it seems like you want to do.


嗯,我从来没有使用过同步绑定列表但现在你提到它,你是对的。我从来没有注意到InvokeRequired和Invoke是ISynchronizeInvoke接口的一部分(每天都学习新的东西)。



所以,我去了ISynchronizeInvoke界面的MSDN页面和我看到这可能会对你有所帮助:



http://msdn.microsoft.com/en-us/library/system.componentmodel.isynchronizeinvoke.aspx [ ^ ]



1.异步,使用BeginInvoke方法。 BeginInvoke启动一个进程,然后立即返回。使用EndInvoke等待BeginInvoke启动的进程完成。



2.同步,使用Invoke方法。 Invoke启动一个进程,等待它完成,然后返回。当控件的主线程与调用线程不同时,使用Invoke将调用编组到正确的线程。



情况2绝对适用于您。尝试使用Invoke而不是BeginInvoke。我希望这对你有用,请告诉我,因为我可能会开始自己使用这样的集合。
Hmm, I've never used an asychronous binding list but now that you mention it, you're right. I never noticed that InvokeRequired and Invoke are part of the ISynchronizeInvoke interface (learn something new every day).

So, I went to the MSDN page on ISynchronizeInvoke interface and I see this that might help you:

http://msdn.microsoft.com/en-us/library/system.componentmodel.isynchronizeinvoke.aspx[^]

1. Asynchronously, by using the BeginInvoke method. BeginInvoke starts a process and then returns immediately. Use EndInvoke to wait until the process started by BeginInvoke completes.

2. Synchronously, by using the Invoke method. Invoke starts a process, waits until it completes, and then returns. Use Invoke when the control's main thread is different from the calling thread to marshal the call to the proper thread.

Situation 2 definitely applies to you. Try using Invoke instead of BeginInvoke. I hope this works for you, let me know because I may start using collections like this myself.


这篇关于帮助System.Reflection.TargetInvocationException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆