void view_ProcessImage(object sender, ProcessThreadNumberEventArgs e)
        {
            ValidationResults results            = Validation.Validate <ProjectSetting>(ps);
            List <string>     validationMessages = new List <string>();

            if (!results.IsValid)
            {
                foreach (ValidationResult vr in results)
                {
                    if (vr.Tag == "Warning")
                    {
                        if (!View.DisplayWarning(vr.Message))
                        {
                            // if user chooses not to continue with warning message, then it is treated as error.
                            validationMessages.Add(vr.Message);
                        }
                    }
                    else
                    {
                        validationMessages.Add(vr.Message);
                    }
                }
            }

            if (validationMessages.Count > 0)
            {
                SetErrorMessage(validationMessages.ToArray());
            }
            else
            {
                this.processing = true;

                System.Diagnostics.Debug.WriteLine("Current Thread: "
                                                   + Thread.CurrentThread.ManagedThreadId
                                                   + " Culture: "
                                                   + Thread.CurrentThread.CurrentCulture.ToString()
                                                   + " before processing.");

                //e.DateTimeFormat = checkDateTimeFormatString(e.DateTimeFormat
                BehaviorSetting bs = new BehaviorSetting()
                {
                    ThreadNumber         = e.ThreadNumber,
                    DateTimeFormatString = checkDateTimeFormatString(e.DateTimeFormat, GetDateTimeFormatStrings())
                };

                // we need to use WaitAll to be notified all jobs from all threads are done,
                // WaitAll will block the current thread, I don't want it happen to main thread,
                // that is the reason we create another thread instead.
                Thread controlThread = new Thread(new ParameterizedThreadStart(engineController));
                // in the situation to use command line to load different culture other than OS' current one,
                // the default culture of new thread will be from OS. We should overwrite it from main thread.
                controlThread.CurrentCulture = Thread.CurrentThread.CurrentCulture;
                controlThread.Start(bs);
            }
        }
        private void engineController(object state)
        {
            BehaviorSetting bs           = (BehaviorSetting)state;
            uint            threadNumber = bs.ThreadNumber;

            AutoResetEvent[] events = new AutoResetEvent[threadNumber];
            for (int i = 0; i < events.Length; i++)
            {
                events[i] = new AutoResetEvent(false);
            }

            engine = new ImageProcessorEngine(this.ps, threadNumber, bs.DateTimeFormatString,
                                              events, View.ExifContainer);

            View.ResetJobSize(engine.JobSize);

            engine.ImageProcessed += new ImageProcessedDelegate(engine_ImageProcessed);
            engine.StartProcess();

            AutoResetEvent.WaitAll(events);

            //this.view.ProcessingStopped();
            this.processing = false;
        }