/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="obj">The object to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void TryGetImageAsync(object obj, GrhImageListAsyncCallback callback, object userState) { if (obj is Grh) { // Grh GetImageAsync((Grh)obj, callback, userState); } else if (obj is GrhData) { // GrhData GetImageAsync((GrhData)obj, callback, userState); } else if (obj is GrhIndex) { // Grhindex GetImageAsync((GrhIndex)obj, callback, userState); } else { // Invalid type if (callback != null) { callback(this, null, ErrorImage, userState); } } }
/// <summary> /// Initializes a new instance of the <see cref="ThreadPoolAsyncCallbackState"/> class. /// </summary> /// <param name="grhData">The <see cref="StationaryGrhData"/>.</param> /// <param name="callback">The callback to invoke when complete.</param> /// <param name="userState">The user state object.</param> /// <param name="wait">If true, performs a spin-wait. If false, generates the <see cref="Image"/> on the thread.</param> /// <param name="bitmap">The unscaled <see cref="Bitmap"/>. Only needed when <paramref name="wait"/> is false.</param> public ThreadPoolAsyncCallbackState(StationaryGrhData grhData, GrhImageListAsyncCallback callback, object userState, bool wait, Bitmap bitmap) { _grhData = grhData; _callback = callback; _userState = userState; _wait = wait; _bitmap = bitmap; }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="grh">The <see cref="Grh"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(Grh grh, GrhImageListAsyncCallback callback, object userState) { if (grh == null) { if (callback != null) { callback(this, null, ErrorImage, userState); } } else { GetImage(grh.CurrentGrhData, true, callback, userState); } }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="gd">The <see cref="GrhData"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(GrhData gd, GrhImageListAsyncCallback callback, object userState) { if (gd == null) { if (callback != null) { callback(this, null, ErrorImage, userState); } } else { GetImage(gd.GetFrame(0), true, callback, userState); } }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="obj">The object to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void TryGetImageAsync(object obj, GrhImageListAsyncCallback callback, object userState) { if (obj is Grh) { // Grh GetImageAsync((Grh)obj, callback, userState); } else if (obj is GrhData) { // GrhData GetImageAsync((GrhData)obj, callback, userState); } else if (obj is GrhIndex) { // Grhindex GetImageAsync((GrhIndex)obj, callback, userState); } else { // Invalid type if (callback != null) callback(this, null, ErrorImage, userState); } }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="gd">The <see cref="StationaryGrhData"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(StationaryGrhData gd, GrhImageListAsyncCallback callback, object userState) { GetImage(gd, true, callback, userState); }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="grh">The <see cref="Grh"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(Grh grh, GrhImageListAsyncCallback callback, object userState) { if (grh == null) { if (callback != null) callback(this, null, ErrorImage, userState); } else GetImage(grh.CurrentGrhData, true, callback, userState); }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="grhIndex">The <see cref="GrhIndex"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(GrhIndex grhIndex, GrhImageListAsyncCallback callback, object userState) { var gd = GrhInfo.GetData(grhIndex); GetImageAsync(gd, callback, userState); }
/// <summary> /// Asynchronously gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="gd">The <see cref="GrhData"/> to get the <see cref="Image"/> for.</param> /// <param name="callback">The <see cref="GrhImageListAsyncCallback"/> to invoke when the operation has finished.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> public void GetImageAsync(GrhData gd, GrhImageListAsyncCallback callback, object userState) { if (gd == null) { if (callback != null) callback(this, null, ErrorImage, userState); } else GetImage(gd.GetFrame(0), true, callback, userState); }
/// <summary> /// Gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="gd">The <see cref="StationaryGrhData"/> to get the <see cref="Image"/> for.</param> /// <param name="async">If true, asynchronous mode will be used. This will return null immediately if the desired /// <see cref="Image"/> has not yet been created.</param> /// <param name="callback">When <see cref="async"/> is false, contains the callback method to invoke when the <see cref="Image"/> /// has been created.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> /// <returns> /// The <see cref="Image"/> for the <paramref name="gd"/>, or null if <paramref name="async"/> is set. /// </returns> Image GetImage(StationaryGrhData gd, bool async, GrhImageListAsyncCallback callback, object userState) { if (gd == null) { if (!async) { // Return the ErrorImage directly return ErrorImage; } else { // Raise the callback and pass the ErrorImage if (callback != null) callback(this, gd, ErrorImage, userState); return null; } } // Get the key var key = GetImageKey(gd); // Get the image from the cache Image img; lock (_imagesSync) { // Check if the image already exists if (!_images.TryGetValue(key, out img)) { // Image does not exist, so add the placeholder since we are about to create it. Placing the placeholder // in there will make sure that no other threads try to create it at the same time. img = null; _images.Add(key, _placeholder); } } if (!async) { if (img != null) { if (img == _placeholder) { // If we got the placeholder image, do a spin-wait until we get the actual image, then return the image. This will // happen when another thread is creating the image. return SpinWaitForImage(key); } else { // Any other non-null image means that the image was already created, so we can just return it immediately return img; } } else { // Create it on this thread and return it when its done return CreateAndInsertImage(key, gd); } } else { if (img != null) { // When we get the placeholder image while in async mode, this is slightly more annoying since we have // to create another thread to spin-wait on if (img == _placeholder) { // Create the thread to spin-wait on... though only if we were given a callback method. Obviously does no // good to wait for the image when there is no callback method. if (callback != null) { var tpacs = new ThreadPoolAsyncCallbackState(gd, callback, userState, true, null); ExecuteOnThreadPool(tpacs); } } else { // But when we get the actual image, we can just invoke the callback directly from this thread. This is the // once scenario where no threads are created in async mode. if (callback != null) callback(this, gd, img, userState); } } else { // NOTE: The asynchronous aspect is less than optimal due to this. // When originally designing this, I was working under the assumption that SFML would be able to deal with the threading // better. Turns out I was wrong. There are probably some other threading issues that would have to be taken into // account, too, like that content can be disposed on the main thread. I could offload more onto the worker thread // than just the rescaling, such as the generation of the original unscaled bitmap, but the biggest gains come from // the ability to offload the actual image loading. I guess its helpful to have at least a little work offloaded // than to be completely synchronous since that does mean multi-core CPUs can load a bit faster. var bmp = CreateUnscaledBitmap(gd); if (bmp == null) { // If the bitmap failed to be created for whatever reason, use the ErrorImage if (callback != null) callback(this, gd, ErrorImage, userState); lock (_imagesSync) { Debug.Assert(_images[key] == _placeholder); _images[key] = ErrorImage; } } else { // Add the Image creation job to the thread pool var tpacs = new ThreadPoolAsyncCallbackState(gd, callback, userState, false, bmp); ExecuteOnThreadPool(tpacs); } } // Async always returns null return null; } }
/// <summary> /// Initializes the <see cref="GrhTreeViewNode"/> class. /// </summary> static GrhTreeViewNode() { _grhImageList = GrhImageList.Instance; _asyncCallback = GrhImageListAsyncCallback; _setNodeImage = SetNodeImage; }
/// <summary> /// Gets the <see cref="Image"/> for the given argument. /// </summary> /// <param name="gd">The <see cref="StationaryGrhData"/> to get the <see cref="Image"/> for.</param> /// <param name="async">If true, asynchronous mode will be used. This will return null immediately if the desired /// <see cref="Image"/> has not yet been created.</param> /// <param name="callback">When <see cref="async"/> is false, contains the callback method to invoke when the <see cref="Image"/> /// has been created.</param> /// <param name="userState">The optional user state object to pass to the <paramref name="callback"/>.</param> /// <returns> /// The <see cref="Image"/> for the <paramref name="gd"/>, or null if <paramref name="async"/> is set. /// </returns> Image GetImage(StationaryGrhData gd, bool async, GrhImageListAsyncCallback callback, object userState) { if (gd == null) { if (!async) { // Return the ErrorImage directly return(ErrorImage); } else { // Raise the callback and pass the ErrorImage if (callback != null) { callback(this, gd, ErrorImage, userState); } return(null); } } // Get the key var key = GetImageKey(gd); // Get the image from the cache Image img; lock (_imagesSync) { // Check if the image already exists if (!_images.TryGetValue(key, out img)) { // Image does not exist, so add the placeholder since we are about to create it. Placing the placeholder // in there will make sure that no other threads try to create it at the same time. img = null; _images.Add(key, _placeholder); } } if (!async) { if (img != null) { if (img == _placeholder) { // If we got the placeholder image, do a spin-wait until we get the actual image, then return the image. This will // happen when another thread is creating the image. return(SpinWaitForImage(key)); } else { // Any other non-null image means that the image was already created, so we can just return it immediately return(img); } } else { // Create it on this thread and return it when its done return(CreateAndInsertImage(key, gd)); } } else { if (img != null) { // When we get the placeholder image while in async mode, this is slightly more annoying since we have // to create another thread to spin-wait on if (img == _placeholder) { // Create the thread to spin-wait on... though only if we were given a callback method. Obviously does no // good to wait for the image when there is no callback method. if (callback != null) { var tpacs = new ThreadPoolAsyncCallbackState(gd, callback, userState, true, null); ExecuteOnThreadPool(tpacs); } } else { // But when we get the actual image, we can just invoke the callback directly from this thread. This is the // once scenario where no threads are created in async mode. if (callback != null) { callback(this, gd, img, userState); } } } else { // NOTE: The asynchronous aspect is less than optimal due to this. // When originally designing this, I was working under the assumption that SFML would be able to deal with the threading // better. Turns out I was wrong. There are probably some other threading issues that would have to be taken into // account, too, like that content can be disposed on the main thread. I could offload more onto the worker thread // than just the rescaling, such as the generation of the original unscaled bitmap, but the biggest gains come from // the ability to offload the actual image loading. I guess its helpful to have at least a little work offloaded // than to be completely synchronous since that does mean multi-core CPUs can load a bit faster. var bmp = CreateUnscaledBitmap(gd); if (bmp == null) { // If the bitmap failed to be created for whatever reason, use the ErrorImage if (callback != null) { callback(this, gd, ErrorImage, userState); } lock (_imagesSync) { Debug.Assert(_images[key] == _placeholder); _images[key] = ErrorImage; } } else { // Add the Image creation job to the thread pool var tpacs = new ThreadPoolAsyncCallbackState(gd, callback, userState, false, bmp); ExecuteOnThreadPool(tpacs); } } // Async always returns null return(null); } }