I use DispatcherTimer
because I need to do an operation every couple of minutes. Inside this I call a BackgroundWorker
to do my work, and then use the dispatcher attached to the timer to update my UI. I'm thinking the error I'm getting has to do with the timer, but I'm not sure. Is the dispatcher done or the backgroundworker? How can I do the ReportProgress inside the foreach?
The error:
This operation has already had OperationCompleted called on it and further calls are illegal.
when doing this:
(sender as BackgroundWorker).ReportProgress((counterTotalSteps / 100) * counterOnStep);
Here is the simplified:
DispatcherTimer dispTimer = new DispatcherTimer();
Dispatcher dispatcher = dispTimer.Dispatcher;
dispTimer.Tick += delegate {dispTimer_Tick(dispatcher); };
dispTimer.Interval = new TimeSpan(0, 0, 45);
dispTimer.Start();
private void DoWork(object sender,Dispatcher dispatcher)
{
int counterTotalSteps = PartialEmployees.Count();
int counterOnStep = 1;
dispatcher.BeginInvoke(new Action(() =>
{
AllEmployees.Clear();
//calling the ReportProgress here works
foreach (var item in PartialEmployees)
{
counterOnStep ++;
//part below throws the error
(sender as BackgroundWorker).ReportProgress((counterTotalSteps / 100) * counterOnStep);
AllEmployees.Add(item);
}
counterOnStep = 0;
}));
}
EDIT: StackTrace:
at System.ComponentModel.AsyncOperation.VerifyNotCompleted()
at System.ComponentModel.AsyncOperation.Post(SendOrPostCallback d, Object arg)
at System.ComponentModel.BackgroundWorker.ReportProgress(Int32 percentProgress, Object userState)
at System.ComponentModel.BackgroundWorker.ReportProgress(Int32 percentProgress)
at testDispatcher.ViewModel.EmployeeListViewModel.<>c__DisplayClass7.<DoWork>b__6() in C:\Users\kozaj\Documents\Visual Studio 2010\Projects\testDispatcher\testDispatcher\ViewModel\EmployeeListViewModel.cs:line 91
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
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.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at testDispatcher.App.Main() in C:\Users\kozaj\Documents\Visual Studio 2010\Projects\testDispatcher\testDispatcher\obj\x86\Debug\App.g.cs:line 50
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()
Sequence of events
I suggest using dispatcher.Invoke (which runs it immediately) on only the steps that actually have UI interaction.