2010-11-18 3 views
2

DispatcherTimer을 사용합니다. 매 2 분마다 작업을해야하기 때문입니다. 이 내에서 BackgroundWorker을 호출하여 내 작업을 수행 한 다음 타이머에 연결된 디스패처를 사용하여 UI를 업데이트합니다. 내가 얻는 오류가 타이머와 관련이 있다고 생각하지만 확실하지 않습니다. 운영자 또는 백그라운드 관리자입니까? foreach 내부에서 ReportProgress를 수행하려면 어떻게해야합니까?ReportProgress를 수행 할 때 BackgroundWorker 또는 (Dispatcher) 작업이 이미 완료되었습니다.

오류 :

This operation has already had OperationCompleted called on it and further calls are illegal.

이러는 :

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 : 스택 트레이스 :

여기

(sender as BackgroundWorker).ReportProgress((counterTotalSteps/100) * counterOnStep); 

은 간략화 "AllEmployees.Clear를();"이벤트 617,451,515,

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() 
+0

스택 추적이란 무엇입니까? – SLaks

+1

왜 BackgroundWorker를 사용하고 있지만 UI 스레드에서 모든 작업을 수행하고 있습니까? – SLaks

+0

이것은 다른 예제에서 구현하기 전에 제대로 작동하는지 확인할 수있는 예제 코드입니다. dipatcher 밖에서 어떤 부분을 움직이시겠습니까? 또한 이러한 목록은 UI에 바인딩됩니다. – LobalOrning

답변

3

순서는

  1. DoWork는
  2. DoWork를두고이라고 디스패처 큐에 넣습니다.
  3. DoWork가 완료되었습니다.
  4. Dispatcher는 "AllEmployees.Clear();" 그 기능을 처리하기 시작합니다.

실제적으로 UI 상호 작용이있는 단계에서만 dispatcher.Invoke (즉시 실행 됨)를 사용하는 것이 좋습니다.

+0

.Invoke()를 사용하면 효과적입니다. 내가하고있는 일은 progressBar를 증가시키는 것이지만, 한번에 (100 %까지) 모든 것을 수행하는 것처럼 보입니다. WorkerProgressChanged()에 중단 점을 넣을 때 foreach가 호출 할 때 호출되지 않고 foreach 후에 호출되는 횟수가 얼마나 많은지에 대해 호출됩니다. 어떤 제안? – LobalOrning

+0

'ReportProgress'는 내부적으로'BeginInvoke'를 호출하여 진행 상황을보고합니다. 끝나면 UI 스레드가 비어있을 때만 게시되는 메시지가 처리됩니다. – SLaks

1

작업이 UI 스레드에서 수행 되었기 때문에 BackgroundWorker를 전혀 사용하지 않아야합니다.

대신 루프 내에서 진행률 막대를 직접 업데이트해야합니다.

+0

내 작업이 UI 스레드에서 수행된다고 할 때, dispTimer_Tick()이 UI 스레드에 있기 때문에 UI 스레드에 BackgroundWorker가 생성 될 때 그렇게 말합니까? – LobalOrning

+0

@Lobal : BackgroundWorker는 백그라운드 스레드에서 실행됩니다. 그러나, 당신은'dispatcher.BeginInvoke'는 무엇을한다고 생각하니? – SLaks

+0

조치를 UI 스레드 대기열에 넣습니다. 목록이 UI에 바인딩되어 있기 때문에 루프를 수행해야합니다. 목록을 새로 고칠 수있는 방법이 다른지 잘 모르겠습니다. 미안 해요. 제 작업이 엉성한 일이라면 저는 아주 새로운 코더입니다. – LobalOrning