//TODO (CR Sept 2010): same comment as with the ProgressGraphic stuff; the API is unclear
        //as to what it is doing (return value) because it's trying to account for the async loading.

        /// <summary>
        /// Attempts to start loading the overlay data asynchronously, if not already loaded.
        /// </summary>
        /// <param name="progress">A value between 0 and 1 indicating the progress of the asynchronous loading operation.</param>
        /// <param name="message">A string message detailing the progress of the asynchronous loading operation.</param>
        /// <returns></returns>
        public bool BeginLoad(out float progress, out string message)
        {
            // update the last access time
            _largeObjectData.UpdateLastAccessTime();

            // if the data is already available without blocking, return success immediately

            //TODO (CR Sept 2010): because unloading the volume involves disposing it, if every operation that uses it
            //isn't in the same lock (e.g. lock(_syncVolumeDataLock)) you could be getting a disposed/null volume here.
            VolumeData volume = _volume;

            if (volume != null)
            {
                message  = SR.MessageFusionComplete;
                progress = 1f;
                return(true);
            }

            lock (_syncLoaderLock)
            {
                message  = SR.MessageFusionInProgress;
                progress = 0;
                if (_volumeLoaderTask == null)
                {
                    // if the data is available now, return success
                    volume = _volume;
                    if (volume != null)
                    {
                        message  = SR.MessageFusionComplete;
                        progress = 1f;
                        return(true);
                    }

                    _volumeLoaderTask = new BackgroundTask(c => this.LoadVolume(c), false, null)
                    {
                        ThreadUICulture = Application.CurrentUICulture
                    };
                    _volumeLoaderTask.Run();
                    _volumeLoaderTask.Terminated += OnVolumeLoaderTaskTerminated;
                }
                else
                {
                    if (_volumeLoaderTask.LastBackgroundTaskProgress != null)
                    {
                        message  = _volumeLoaderTask.LastBackgroundTaskProgress.Progress.Message;
                        progress = _volumeLoaderTask.LastBackgroundTaskProgress.Progress.Percent / 100f;
                    }
                }
            }
            return(false);
        }
        private void UnloadVolume()
        {
            // wait for synchronized access
            lock (_syncVolumeDataLock)
            {
                // dump our data
                if (_volume != null)
                {
                    _volume.Dispose();
                    _volume = null;
                }

                // update our stats
                _largeObjectData.BytesHeldCount   = 0;
                _largeObjectData.LargeObjectCount = 0;

                // unregister with memory manager
                MemoryManager.Remove(this);
            }

            this.OnUnloaded();
        }
        private VolumeData LoadVolume(IBackgroundTaskContext context)
        {
            // wait for synchronized access
            lock (_syncVolumeDataLock)
            {
                // if the data is now available, return it immediately
                // (i.e. we were blocked because we were already reading the data)
                if (_volume != null)
                {
                    return(_volume);
                }

                // load the volume data
                if (context == null)
                {
                    _volume = VolumeData.Create(_frames);
                }
                else
                {
                    _volume = VolumeData.Create(_frames, (n, count) => context.ReportProgress(new BackgroundTaskProgress(n, count, SR.MessageFusionInProgress)));
                }

                // update our stats
                _largeObjectData.BytesHeldCount   = 2 * _volume.SizeInVoxels;
                _largeObjectData.LargeObjectCount = 1;
                _largeObjectData.UpdateLastAccessTime();

                // regenerating the volume data is easy when the source frames are already in memory!
                _largeObjectData.RegenerationCost = RegenerationCost.Low;

                // register with memory manager
                MemoryManager.Add(this);

                return(_volume);
            }
        }