void ThreadPoolWorkerFileEnumeration(object state)
        {
            System.Diagnostics.Debug.WriteLine("ThreadPoolWorkerFileEnumeration:: Start");

            ResetPublicProperties();

            IsScanInProgress = true;

            _start = DateTime.Now;
            System.Diagnostics.Debug.WriteLine("START:: " + _start.ToString());


            MainViewModel mvm = state as MainViewModel;

            _dirFileEnumeration.EnumerateFiles(mvm.FolderPath);

            /* remove single entries of hashes
             * loop in reverse (bottom up) else when removing index from start, ordering gets corrupted.
             */
            for (int i = _HashInfoFiles.Count - 1; i >= 0; i--)
            {
                KeyValuePair <string, List <FileDetail> > keyvalue = _HashInfoFiles.ElementAt(i);

                if (keyvalue.Value.Count < 2)
                {
                    _HashInfoFiles.Remove(keyvalue.Key);
                }
                else
                {
                    foreach (var item in keyvalue.Value)
                    {
                        Application.Current.Dispatcher.Invoke((Action)(() =>
                        {
                            // access in UI thread.
                            DuplicateFileList.Add(item);
                        }));
                    }
                }
            }

            _FileSizeInfo.Clear();
            _HashInfoFiles.Clear();

            _end = DateTime.Now;
            System.Diagnostics.Debug.WriteLine("END:: " + _end.ToString());
            // 3 decimal only
            FileEnumTotalTimeForScan = (_end - _start).ToString();

            System.Diagnostics.Debug.WriteLine("TOTAL ELAPSED TIME:: " + (_end - _start).ToString());

            IsScanInProgress = false;
            System.Diagnostics.Debug.WriteLine("ThreadPoolWorkerFileEnumeration:: End");
        }
        void ResetPublicProperties()
        {
            NumberOfBuckets           = 0;
            HashCurrentFile           = null;
            FileEnumCurrentFile       = null;
            FileEnumTotalFilesScanned = 0;
            FileEnumTotalTimeForScan  = null;

            _FileSizeInfo.Clear();
            _HashInfoFiles.Clear();

            Application.Current.Dispatcher.Invoke((Action)(() =>
            {
                // Observable collection needs to be accessed in UI thread.
                DuplicateFileList.Clear();
                ErrorList.Clear();
            }));
        }
        void ThreadPoolWorkerDeleteSelectedItems(object state)
        {
            System.Collections.IList list = (System.Collections.IList)state;

            for (int i = list.Count - 1; i >= 0; i--)
            {
                FileDetail fd = (FileDetail)list[i];

                try
                {
                    File.Delete(fd.FullFilePath);

                    // if exception happens the error list will show which file is not deleted.
                    // The item will not be removed from the list as well. Helps if file is in use
                    // and user can close it and try again.
                    Application.Current.Dispatcher.Invoke((Action)(() =>
                    {
                        // access in UI thread.
                        DuplicateFileList.Remove(fd);
                    }));
                }
                catch (Exception Ex)
                {
                    /*
                     * Update the list to reflect the errors when deleting file.
                     */
                    Application.Current.Dispatcher.Invoke((Action)(() =>
                    {
                        // access in UI thread.
                        ErrorList.Add(Ex.Message);
                    }));

                    System.Diagnostics.Debug.WriteLine(Ex.Message);
                }
            }

            System.Diagnostics.Debug.WriteLine("ThreadPoolWorkerDeleteSelectedItems..");
        }