661 lines
26 KiB
HTML
661 lines
26 KiB
HTML
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|||
|
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|||
|
|
<head>
|
|||
|
|
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
|||
|
|
<title>Loading Thumbnails</title>
|
|||
|
|
<link href="style.css" rel="stylesheet" type="text/css">
|
|||
|
|
<link href="prettify.css" type="text/css" rel="stylesheet">
|
|||
|
|
<script type="text/javascript" src="prettify.js"></script><script type="text/javascript" src="lang-vb.js"></script><link href="../resources/main.css" media="screen" rel="stylesheet" type="text/css">
|
|||
|
|
</head>
|
|||
|
|
<body onload="prettyPrint()"><div class="placing">
|
|||
|
|
<br><table class="navigation"><tr>
|
|||
|
|
<td class="navigation-previous"><a href="chapter-layout.html"><strong>
|
|||
|
|
« Layout</strong></a></td>
|
|||
|
|
<td class="navigation-index"><a href="../../../better-thumbnail-browser/documentation.html"><strong>Index</strong></a></td>
|
|||
|
|
<td class="navigation-next"><a href="chapter-text-formatting.html"><strong>Text Formatting »
|
|||
|
|
</strong></a></td>
|
|||
|
|
</tr></table>
|
|||
|
|
<br><h1>Loading Thumbnails</h1>
|
|||
|
|
<div class="banner">
|
|||
|
|
<a href="../../../better-thumbnail-browser.html"><img src="../resources/better-thumbnail-browser-overview.gif" alt="Better Thumbnail Browser" class="ss"></a>
|
|||
|
|
<div class="inside">
|
|||
|
|
<div class="text">Better Thumbnail Browser for .NET (C#, VB) - Image thumbnail viewing and loading control</div>
|
|||
|
|
<span class="dbtn-c dbtn-hilight"><span class="dbtn-w"><a href="../../../betterthumbnailbrowser.exe" class="dbtn">Download</a></span></span>
|
|||
|
|
<span class="dbtn-c"><span class="dbtn-w"><a href="../../../better-thumbnail-browser.html" class="dbtn">More Info</a></span></span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Loading Images from a Folder</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>You can populate Better Thumbnail Browser with auto-population in
|
|||
|
|
case you want to display images from an image folder:</p>
|
|||
|
|
|
|||
|
|
<p><strong>C#</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-cs">thumbnailBrowser.Path = "c:\\images";</code></pre>
|
|||
|
|
|
|||
|
|
<p><strong>Visual Basic</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-vb">thumbnailBrowser.Path = "c:\images"</code></pre>
|
|||
|
|
|
|||
|
|
<p>This will automatically add items to Better Thumbnail Browser and
|
|||
|
|
starts loading them using default image loading provider:</p>
|
|||
|
|
|
|||
|
|
<p class="images"><img src="using-auto-populate.png"></p>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Starting, Stopping and Restarting Loading</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>You can control item loading by calling <span class="code">StartLoading()</span>,
|
|||
|
|
<span class="code">StopLoading()</span> and <span class="code">RestartLoading()</span>
|
|||
|
|
methods.</p>
|
|||
|
|
|
|||
|
|
<p>The <span class="code">StartLoading()</span> method is asynchronous, so the code
|
|||
|
|
will continue after the call and the thumbnail items will be loaded on a
|
|||
|
|
separate thread.</p>
|
|||
|
|
|
|||
|
|
<p>The <span class="code">StopLoading()</span> method is synchronous - it will wait
|
|||
|
|
until current item finishes loading and then stops.</p>
|
|||
|
|
|
|||
|
|
<p>The <span class="code">RestartLoading()</span> method has an override with
|
|||
|
|
<span class="code">LoadingRestartOptions</span> parameter. It can have the following
|
|||
|
|
values:</p>
|
|||
|
|
|
|||
|
|
<ul style="list-style:none">
|
|||
|
|
<li>
|
|||
|
|
<span class="code">None</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Restart loading if already running. Do not start loading if
|
|||
|
|
not running.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">StopLoading</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Stop loading and then start from beginning.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">CanStartLoading</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Restart loading if already running. Start loading even if not
|
|||
|
|
running.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<p>When calling <span class="code">RestartLoading()</span> method without
|
|||
|
|
parameters, the <span class="code">LoadingRestartOptions.None</span> is used.</p>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Loading Events</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>During the loading process, two events are raised by the Better
|
|||
|
|
ThumbnailBrowser control:</p>
|
|||
|
|
|
|||
|
|
<ul style="list-style:none">
|
|||
|
|
<li>
|
|||
|
|
<span class="code">ItemLoaded</span><ul style="list-style:none"><li>
|
|||
|
|
<p>This event is raised whenever a single item is loaded by a
|
|||
|
|
loading provider. The event can be raised multiple times for a
|
|||
|
|
single item if a multi-pass loading (see section <strong><em><a href="chapter-loading.html#multi-pass-loading">Multi-pass Loading</a></em></strong>) is used.
|
|||
|
|
Event data contains loaded item instance, pass index, total number
|
|||
|
|
of passes and order in which the item is loaded (the order can be
|
|||
|
|
different from the item index, see section <strong><em><a href="chapter-loading.html#custom-loading-order">Custom Loading
|
|||
|
|
Order</a></em></strong>).</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">LoadingFinised</span><ul style="list-style:none"><li>
|
|||
|
|
<p>This event is raised when thumbnail item loading finishes for
|
|||
|
|
whatever reason (no more items to load, loading cancelled by the
|
|||
|
|
user, loading failed). Event data contains index of item on which
|
|||
|
|
the loading finished/stopped (<span class="code">LoadingFinishReason</span>
|
|||
|
|
enumeration), reason why the loading ended and
|
|||
|
|
<span class="code">System.Exception</span> instance in case the loading failed
|
|||
|
|
because exception occured on the loading thread.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<h2>Loading Options</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Refreshing Delay</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>When large number of small thumbnails are loaded, or when loading
|
|||
|
|
each thumbnail is quick, it is inefficient to refresh control after
|
|||
|
|
every single item is loaded. Instead, a timer looks for loaded items in
|
|||
|
|
a predefined interval and refreshes the control only if any items get
|
|||
|
|
loaded. By default, the interval is set to 250 millisecons, but you can
|
|||
|
|
set your own value through <span class="code">RefreshDelay</span> property. When you
|
|||
|
|
set property value to <span class="code">0</span>, the control will be refreshed
|
|||
|
|
after every item loaded.</p>
|
|||
|
|
|
|||
|
|
<p>Better Thumbnail Browser uses <span class="code">System.Threading.Timer</span>,
|
|||
|
|
so its accurracy is in order of tens of milliseconds.</p>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Loading Thread Options</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>You can setup thumbnail item loading thread by setting the
|
|||
|
|
following properties:</p>
|
|||
|
|
|
|||
|
|
<ul style="list-style:none">
|
|||
|
|
<li>
|
|||
|
|
<span class="code">LoadingThreadIsBackground</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Specifies whether the item loading thread runs as a
|
|||
|
|
background thread.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">LoadingThreadPriority</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Specified item loading thread priority
|
|||
|
|
(<span class="code">System.Threading.ThreadPriority</span>).</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<h2>Skipping Individual Items</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>If you want <strong><em>not to</em></strong> load specific thumbnail
|
|||
|
|
items, set <span class="code">BetterThumbnailBrowserItem.Skip</span> property to
|
|||
|
|
<span class="code">true</span>.</p>
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Loading Providers</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>Thumbnail item loading is performed by so called <strong><em>loading
|
|||
|
|
providers</em></strong> (instances of <span class="code">LoadingProvider</span>
|
|||
|
|
class).</p>
|
|||
|
|
|
|||
|
|
<p>These instances are listed in the <span class="code">LoadingProviders</span>
|
|||
|
|
property. In case there is more than one loading provider, a multiple
|
|||
|
|
passes over the thumbnail items are done, one for each loading
|
|||
|
|
provider.</p>
|
|||
|
|
|
|||
|
|
<p>Better Thumbnail Browser have two bases classes for deriving your own
|
|||
|
|
loading providers:</p>
|
|||
|
|
|
|||
|
|
<ul style="list-style:none">
|
|||
|
|
<li>
|
|||
|
|
<span class="code">CustomLoadingProvider</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Intended for loading non-image data.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">ImageLoadingProvider</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Intended for loading image thumbnails.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<p>The both of these classes are derived from
|
|||
|
|
<span class="code">LoadingProvider</span> class and implement a <span class="code">LoadItem</span>
|
|||
|
|
method. In this method, the loader calls <span class="code">LoadItemAsync</span>
|
|||
|
|
method, which have to be provided by the user as well as the
|
|||
|
|
<span class="code">LoadItemSync</span> method. The difference between these two methods
|
|||
|
|
is that <span class="code">LoadItemAsync</span> is called on the (background) loader
|
|||
|
|
thread and the <span class="code">LoadItemSync</span> is then called on the UI
|
|||
|
|
(foreground) thread.</p>
|
|||
|
|
|
|||
|
|
<p>Only <span class="code">LoadItemAsync</span> and <span class="code">LoadItemSync</span>
|
|||
|
|
methods need to be implemented by the user.</p>
|
|||
|
|
|
|||
|
|
<p>There is also <span class="code">LoadItemsSync</span> method which is used by
|
|||
|
|
<span class="code">LoadItem</span> when timer is used (see <span class="code">RefreshDelay</span>
|
|||
|
|
property), in that case, the loading provider calls only
|
|||
|
|
<span class="code">LoadItemAsync</span> and stores the result data, and then performs
|
|||
|
|
synchronization and calls <span class="code">LoadItemSync</span> in a batch.</p>
|
|||
|
|
|
|||
|
|
<h2>Loading Image Thumbnails in Better Thumbnail Browser</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>Thumbnail loading is designed to be fast and effective.</p>
|
|||
|
|
|
|||
|
|
<p>First of all, images need not to be loaded in full resolution and
|
|||
|
|
resized. Instead, you can load image in lower resolution or simply get
|
|||
|
|
low resolution version already available. For example, the default image
|
|||
|
|
loading provider in Better Thumbnail Browser makes use of existing image
|
|||
|
|
thumbnails in JPEG image, avoiding resizing.</p>
|
|||
|
|
|
|||
|
|
<p>You can still load images in full resolution. These images will be
|
|||
|
|
present in <span class="code">BetterThumbnailBrowser.Image</span> property in full
|
|||
|
|
resolution, but will be resized internally for viewing.</p>
|
|||
|
|
|
|||
|
|
<p>The thumbnail items can be zoomed and images may need to be
|
|||
|
|
reloaded in higher resolution. The loading mechanism of Better
|
|||
|
|
ThumbnailBrowser never reloads images if a full resolution is already
|
|||
|
|
loaded (smaller image gets centered in the thumbnail item instead). It
|
|||
|
|
also avoid reloading if user provided image of high-enough resolution.
|
|||
|
|
Of course, if you provide image in full resolution, then every thumbnail
|
|||
|
|
item gets loaded just once. To determine what "full resolution" means,
|
|||
|
|
there is a <span class="code">maximumImageSize</span> property in the loading method.
|
|||
|
|
One provides loaded image and informs about the full resolution. You can
|
|||
|
|
also set <span class="code">maximumImageSize</span> property to the same size as
|
|||
|
|
thumbnail image, but your image will not be reloaded in higher
|
|||
|
|
resolution if needed (and get centered in thumbnail items
|
|||
|
|
instead).</p>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Custom Image Loader</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>We will illustrate how to implement a minimalist image loading
|
|||
|
|
provider. It assumes that every item contains path to image file in its
|
|||
|
|
<span class="code">Path</span> property:</p>
|
|||
|
|
|
|||
|
|
<p><strong>C#</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-cs">class MyImageLoadingProvider : ImageLoadingProvider
|
|||
|
|
{
|
|||
|
|
public MyLoadingProvider(BetterThumbnailBrowser thumbnailBrowser)
|
|||
|
|
: base(thumbnailBrowser)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void LoadItemAsync(
|
|||
|
|
BetterThumbnailBrowserItem item,
|
|||
|
|
Size targetImageSize,
|
|||
|
|
out Image image,
|
|||
|
|
out Size maximumImageSize,
|
|||
|
|
out ILoadingProviderData data)
|
|||
|
|
{
|
|||
|
|
image = Image.FromFile(item.Path);
|
|||
|
|
maximumImageSize = image.Size;
|
|||
|
|
data = null;
|
|||
|
|
}
|
|||
|
|
}</code></pre>
|
|||
|
|
|
|||
|
|
<p><strong>Visual Basic</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-vb">Class MyImageLoadingProvider
|
|||
|
|
Inherits ImageLoadingProvider
|
|||
|
|
|
|||
|
|
Public Sub New(thumbnailBrowser As BetterThumbnailBrowser)
|
|||
|
|
MyBase.New(thumbnailBrowser)
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
Protected Overrides Sub LoadItemAsync(
|
|||
|
|
item As BetterThumbnailBrowserItem,
|
|||
|
|
targetImageSize As Size,
|
|||
|
|
ByRef image As Image,
|
|||
|
|
ByRef maximumImageSize As Size,
|
|||
|
|
ByRef data As ILoadingProviderData)
|
|||
|
|
|
|||
|
|
image = Image.FromFile(item.Path)
|
|||
|
|
maximumImageSize = image.Size
|
|||
|
|
data = Nothing
|
|||
|
|
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
End Class</code></pre>
|
|||
|
|
|
|||
|
|
<p>As you can see, the implementation is very simple.</p>
|
|||
|
|
|
|||
|
|
<p>The entire code of <span class="code">LoadItemAsync</span> consists of just
|
|||
|
|
providing these three parameters:</p>
|
|||
|
|
|
|||
|
|
<ul style="list-style:none">
|
|||
|
|
<li>
|
|||
|
|
<span class="code">image</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Loaded thumbnail image.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">maximumImageSize </span><ul style="list-style:none"><li>
|
|||
|
|
<p>Maximum allowed thumbnail size. This is actually size of a
|
|||
|
|
full resolution image, even if you have loaded smaller image (a
|
|||
|
|
thumbnail). This value informs loaded that there is a higher
|
|||
|
|
resolution available and it can re-load image in higher resolution
|
|||
|
|
if needed.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">data</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Custom non-image data we would like to pass to UI thread. We
|
|||
|
|
can use any user types, they only need to implement trivial
|
|||
|
|
<span class="code">ILoadingProviderData</span> interface.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<p>The <span class="code">LoadItemSync</span> method need not to be provided by
|
|||
|
|
the user since it is already implemented in the
|
|||
|
|
<span class="code">ImageLoadingProvider</span>. The default implementation only takes
|
|||
|
|
the <span class="code">image</span> and <span class="code">maximumImageSize</span> and sets it
|
|||
|
|
into respective properties of item:
|
|||
|
|
<span class="code">BetterThumbnailBrowserItem.Image</span> and
|
|||
|
|
<span class="code">BetterThumbnailBrowserItem.MaximumImageSize</span>.</p>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Loading Non-image Data</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>Sometimes one would like to load other than image data - for
|
|||
|
|
example: metadata embedded in photos, file information, retrieve item
|
|||
|
|
info from remote database etc.</p>
|
|||
|
|
|
|||
|
|
<p>This is where <span class="code">CustomLoadingProvider</span> comes into place.
|
|||
|
|
It is more general, so it can be used for loading images as well. User
|
|||
|
|
have to provide both <span class="code">LoadImageAsync</span> and
|
|||
|
|
<span class="code">LoadItemSync</span> methods:</p>
|
|||
|
|
|
|||
|
|
<p><strong>C#</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-cs">class MyCustomLoadingProvider : CustomLoadingProvider
|
|||
|
|
{
|
|||
|
|
public MyCustomLoadingProvider(BetterThumbnailBrowser thumbnailBrowser)
|
|||
|
|
: base(thumbnailBrowser)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void LoadItemAsync(
|
|||
|
|
BetterThumbnailBrowserItem item,
|
|||
|
|
Size targetImageSize,
|
|||
|
|
out ILoadingProviderData data)
|
|||
|
|
{
|
|||
|
|
// obtain custom data (this runs on background thread)
|
|||
|
|
MyLoadingProviderData myLoadingProviderData = /* obtain the data here */;
|
|||
|
|
|
|||
|
|
data = myLoadingProviderData;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void LoadItemSync(BetterThumbnailBrowserItem item, ILoadingProviderData data)
|
|||
|
|
{
|
|||
|
|
MyLoadingProviderData myLoadingProviderData = (MyLoadingProviderData)data;
|
|||
|
|
|
|||
|
|
// set loaded data to item (this runs on main thread)
|
|||
|
|
item.Text = myLoadingProviderData.Label;
|
|||
|
|
item.ToolTips.Add(new BetterListViewToolTipInfo(BetterListViewToolTipLocation.Image, myLoadingProviderData.Description));
|
|||
|
|
}
|
|||
|
|
}</code></pre>
|
|||
|
|
|
|||
|
|
<p><strong>Visual Basic</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-vb">Class MyCustomLoadingProvider
|
|||
|
|
Inherits CustomLoadingProvider
|
|||
|
|
|
|||
|
|
Public Sub New(thumbnailBrowser As BetterThumbnailBrowser)
|
|||
|
|
MyBase.New(thumbnailBrowser)
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
Protected Overrides Sub LoadItemAsync(item As BetterThumbnailBrowserItem, targetImageSize As Size, ByRef data As ILoadingProviderData)
|
|||
|
|
|
|||
|
|
' obtain custom data (this runs on background thread)
|
|||
|
|
Dim myLoadingProviderData As MyLoadingProviderData = ' obtain the data here
|
|||
|
|
|
|||
|
|
data = myLoadingProviderData
|
|||
|
|
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
Protected Overrides Sub LoadItemSync(item As BetterThumbnailBrowserItem, data As ILoadingProviderData)
|
|||
|
|
|
|||
|
|
Dim myLoadingProviderData As MyLoadingProviderData = DirectCast(data, MyLoadingProviderData)
|
|||
|
|
|
|||
|
|
' set loaded data to item (this runs on main thread)
|
|||
|
|
item.Text = myLoadingProviderData.Label
|
|||
|
|
item.ToolTips.Add(New BetterListViewToolTipInfo(BetterListViewToolTipLocation.Image, myLoadingProviderData.Description))
|
|||
|
|
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
End Class</code></pre>
|
|||
|
|
|
|||
|
|
<p>As you can see, we have used custom type
|
|||
|
|
<span class="code">MyLoadingProviderData</span> to hold loaded data, which is passed
|
|||
|
|
to foreground thread to further processing. This type implements
|
|||
|
|
<span class="code">ILoadingProviderData</span> - an empty interface - so its code is
|
|||
|
|
very simple:</p>
|
|||
|
|
|
|||
|
|
<p><strong>C#</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-cs">class MyLoadingProviderData : ILoadingProviderData
|
|||
|
|
{
|
|||
|
|
public string Label
|
|||
|
|
{
|
|||
|
|
get;
|
|||
|
|
set;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public string Description
|
|||
|
|
{
|
|||
|
|
get;
|
|||
|
|
set;
|
|||
|
|
}
|
|||
|
|
}</code></pre>
|
|||
|
|
|
|||
|
|
<p><strong>Visual Basic</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-vb">Class MyLoadingProviderData
|
|||
|
|
Implements ILoadingProviderData
|
|||
|
|
|
|||
|
|
Public Property Label() As String
|
|||
|
|
Get
|
|||
|
|
Return label
|
|||
|
|
End Get
|
|||
|
|
Set
|
|||
|
|
label = Value
|
|||
|
|
End Set
|
|||
|
|
End Property
|
|||
|
|
|
|||
|
|
Public Property Description() As String
|
|||
|
|
Get
|
|||
|
|
Return description
|
|||
|
|
End Get
|
|||
|
|
Set
|
|||
|
|
description = Value
|
|||
|
|
End Set
|
|||
|
|
End Property
|
|||
|
|
|
|||
|
|
Private label As String
|
|||
|
|
Private description As String
|
|||
|
|
|
|||
|
|
End Class</code></pre>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>
|
|||
|
|
<a name="custom-loading-order" id="custom-loading-order"></a>Custom Loading
|
|||
|
|
Order</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>You can specify custom order in which the items will be loaded by
|
|||
|
|
setting an <span class="code">IComparer<BetterThumbnailBrowserItem></span>
|
|||
|
|
instance in the <span class="code">LoadingProvider.ItemComparer</span> property. This
|
|||
|
|
can result in loading images in order you want:</p>
|
|||
|
|
|
|||
|
|
<p></p>
|
|||
|
|
<p class="images"><img src="loading-custom-order.png"></p>
|
|||
|
|
|
|||
|
|
<p>For example, we would like to load visible items first, then all
|
|||
|
|
the others. This can be done with the following comparer:</p>
|
|||
|
|
|
|||
|
|
<p><strong>C#</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-cs">class CustomOrderItemComparer : IComparer<BetterThumbnailBrowserItem>
|
|||
|
|
{
|
|||
|
|
private readonly BetterThumbnailBrowser thumbnailBrowser;
|
|||
|
|
|
|||
|
|
public CustomOrderItemComparer(BetterThumbnailBrowser thumbnailBrowser)
|
|||
|
|
{
|
|||
|
|
this.thumbnailBrowser = thumbnailBrowser;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int IComparer<BetterThumbnailBrowserItem>.Compare(BetterThumbnailBrowserItem itemA, BetterThumbnailBrowserItem itemB)
|
|||
|
|
{
|
|||
|
|
// get put visible item indices in sorted array
|
|||
|
|
ReadOnlyCollection<BetterListViewItem> visibleItems = this.thumbnailBrowser.VisibleItems;
|
|||
|
|
int[] visibleIndices = new int[visibleItems.Count];
|
|||
|
|
|
|||
|
|
for (int indexItem = 0; indexItem < visibleItems.Count; indexItem++)
|
|||
|
|
{
|
|||
|
|
visibleIndices[indexItem] = visibleItems[indexItem].Index;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Array.Sort(visibleIndices);
|
|||
|
|
|
|||
|
|
int valueA = ((Array.BinarySearch(visibleIndices, itemA.Index) >= 0) ? 0 : 1);
|
|||
|
|
int valueB = ((Array.BinarySearch(visibleIndices, itemB.Index) >= 0) ? 0 : 1);
|
|||
|
|
|
|||
|
|
// compare items according to their visibility
|
|||
|
|
int result = valueA.CompareTo(valueB);
|
|||
|
|
|
|||
|
|
if (result != 0)
|
|||
|
|
{
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// compare items according to their indices
|
|||
|
|
valueA = itemA.Index;
|
|||
|
|
valueB = itemB.Index;
|
|||
|
|
|
|||
|
|
return valueA.CompareTo(valueB);
|
|||
|
|
}
|
|||
|
|
}</code></pre>
|
|||
|
|
|
|||
|
|
<p><strong>Visual Basic</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-vb">Class CustomOrderItemComparer
|
|||
|
|
Implements IComparer(Of BetterThumbnailBrowserItem)
|
|||
|
|
|
|||
|
|
Private ReadOnly thumbnailBrowser As BetterThumbnailBrowser
|
|||
|
|
|
|||
|
|
Public Sub New(thumbnailBrowser As BetterThumbnailBrowser)
|
|||
|
|
Me.thumbnailBrowser = thumbnailBrowser
|
|||
|
|
End Sub
|
|||
|
|
|
|||
|
|
Private Function IComparer_Compare(itemA As BetterThumbnailBrowserItem, itemB As BetterThumbnailBrowserItem) As Integer Implements IComparer(Of BetterThumbnailBrowserItem).Compare
|
|||
|
|
|
|||
|
|
' get put visible item indices in sorted array
|
|||
|
|
Dim visibleItems As ReadOnlyCollection(Of BetterListViewItem) = Me.thumbnailBrowser.VisibleItems
|
|||
|
|
Dim visibleIndices As Integer() = New Integer(visibleItems.Count - 1) {}
|
|||
|
|
|
|||
|
|
For indexItem As Integer = 0 To visibleItems.Count - 1
|
|||
|
|
visibleIndices(indexItem) = visibleItems(indexItem).Index
|
|||
|
|
Next
|
|||
|
|
|
|||
|
|
Array.Sort(visibleIndices)
|
|||
|
|
|
|||
|
|
Dim valueA As Integer = (If((Array.BinarySearch(visibleIndices, itemA.Index) >= 0), 0, 1))
|
|||
|
|
Dim valueB As Integer = (If((Array.BinarySearch(visibleIndices, itemB.Index) >= 0), 0, 1))
|
|||
|
|
|
|||
|
|
' compare items according to their visibility
|
|||
|
|
Dim result As Integer = valueA.CompareTo(valueB)
|
|||
|
|
|
|||
|
|
If result <> 0 Then
|
|||
|
|
Return result
|
|||
|
|
End If
|
|||
|
|
|
|||
|
|
' compare items according to their indices
|
|||
|
|
valueA = itemA.Index
|
|||
|
|
valueB = itemB.Index
|
|||
|
|
|
|||
|
|
Return valueA.CompareTo(valueB)
|
|||
|
|
End Function
|
|||
|
|
|
|||
|
|
End Class</code></pre>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>Automatic Restaring on Scroll, Resize and Thumbnail Zoom</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>Sometimes we need to restart loading because of scrolling or
|
|||
|
|
resizing the control, or when thumbnails are zoomed. In the above
|
|||
|
|
example, we have loaded visible items first. When user scrolls the
|
|||
|
|
control, this set of visible items changes and hence we would like to
|
|||
|
|
restart loading.</p>
|
|||
|
|
|
|||
|
|
<p>For example, we load thumbnails only at the necessary resolution.
|
|||
|
|
But when the user resizes the thumbnails, we need to reload them in
|
|||
|
|
higher resolution.</p>
|
|||
|
|
|
|||
|
|
<p>Another case is that we use custom item loading order such that
|
|||
|
|
visible items are loaded first. When user scrolls the control, the order
|
|||
|
|
is changed and we need to restart loading.</p>
|
|||
|
|
|
|||
|
|
<p>This functionality is provided by Better Thumbnail Browser. You
|
|||
|
|
only need to set the following boolean properties to
|
|||
|
|
<span class="code">true</span>:</p>
|
|||
|
|
|
|||
|
|
<ul style="list-style:none">
|
|||
|
|
<li>
|
|||
|
|
<span class="code">LoadingProvider.RestartOnScroll</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Restart loading when the control is scrolled or
|
|||
|
|
resized.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
<li>
|
|||
|
|
<span class="code">ImageLoadingProvider.RestartOnExpand</span><ul style="list-style:none"><li>
|
|||
|
|
<p>Restart loading when thumbnails are enlarged in size.</p>
|
|||
|
|
</li></ul>
|
|||
|
|
</li>
|
|||
|
|
</ul>
|
|||
|
|
<h2>Safe Cross-threaded Operations</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>Better Thumbnail Browser uses two mechanisms for thread
|
|||
|
|
synchronization: <span class="code">Control.Invoke</span> and
|
|||
|
|
<span class="code">Mutex</span>.</p>
|
|||
|
|
|
|||
|
|
<p>The <span class="code">Control.Invoke</span> is used in
|
|||
|
|
<span class="code">LoadingProvider.LoadItem</span> method. Here a
|
|||
|
|
<span class="code">BetterThumbnailBrowser</span> instance is used as an synchronization
|
|||
|
|
object, then <span class="code">LoadItemSync</span> is called so that images and other
|
|||
|
|
data can be set to items on UI thread.</p>
|
|||
|
|
|
|||
|
|
<p><span class="code">Mutex</span> is used whenever Better Thumbnail Browser works
|
|||
|
|
with item data. When you work with items on both loader thread and UI
|
|||
|
|
thread, use <span class="code">BetterThumbnailBrowserItem.SyncRoot</span> as the
|
|||
|
|
synchronization object. Here is a sample of safely setting
|
|||
|
|
<span class="code">Path</span> property of
|
|||
|
|
<span class="code">BetterThumbnailBrowserItem</span>:</p>
|
|||
|
|
|
|||
|
|
<p><strong>C#</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-cs">lock (item.SyncRoot)
|
|||
|
|
{
|
|||
|
|
item.Path = path;
|
|||
|
|
}</code></pre>
|
|||
|
|
|
|||
|
|
<p><strong>Visual Basic</strong></p>
|
|||
|
|
<pre class="prettyprint"><code class="lang-vb">SyncLock item.SyncRoot
|
|||
|
|
item.Path = path
|
|||
|
|
End SyncLock</code></pre>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<h2>
|
|||
|
|
<a name="multi-pass-loading" id="multi-pass-loading"></a>Multi-pass Loading</h2>
|
|||
|
|
|
|||
|
|
|
|||
|
|
<p>In case you need to load items in multiple sweeps, you can set
|
|||
|
|
multiple instances of <span class="code">LoadingProvider</span> in the
|
|||
|
|
<span class="code">LoadingProviders</span> property. The
|
|||
|
|
<strong><em>MultiPassLoadingSample</em></strong> uses several instances of a
|
|||
|
|
custom loading provider, each with different image quality setting. The
|
|||
|
|
result is that paimages are loaded in successively higher levels of
|
|||
|
|
detail:</p>
|
|||
|
|
|
|||
|
|
<p class="images"><img src="loading-multipass.png"></p>
|
|||
|
|
|
|||
|
|
<p>You can in which pass any item currently resides by reading the
|
|||
|
|
<span class="code">BetterThumbnailBrowserItem.PassIndex</span> property. When item
|
|||
|
|
loading is restarted, the items are loaded from their current pass. To
|
|||
|
|
load all items again from scratch, set the <span class="code">PassIndex</span> property
|
|||
|
|
to <span class="code">0</span> and then restart item loading.</p>
|
|||
|
|
|
|||
|
|
<br><div class="banner">
|
|||
|
|
<a href="../../../better-thumbnail-browser.html"><img src="../resources/better-thumbnail-browser-overview.gif" alt="Better Thumbnail Browser" class="ss"></a>
|
|||
|
|
<div class="inside">
|
|||
|
|
<div class="text">Better Thumbnail Browser for .NET (C#, VB) - Image thumbnail viewing and loading control</div>
|
|||
|
|
<span class="dbtn-c dbtn-hilight"><span class="dbtn-w"><a href="../../../betterthumbnailbrowser.exe" class="dbtn">Download</a></span></span>
|
|||
|
|
<span class="dbtn-c"><span class="dbtn-w"><a href="../../../better-thumbnail-browser.html" class="dbtn">More Info</a></span></span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<table class="navigation"><tr>
|
|||
|
|
<td class="navigation-previous"><a href="chapter-layout.html"><strong>
|
|||
|
|
« Layout</strong></a></td>
|
|||
|
|
<td class="navigation-index"><a href="../../../better-thumbnail-browser/documentation.html"><strong>Index</strong></a></td>
|
|||
|
|
<td class="navigation-next"><a href="chapter-text-formatting.html"><strong>Text Formatting »
|
|||
|
|
</strong></a></td>
|
|||
|
|
</tr></table>
|
|||
|
|
<br><table class="footer"><tr>
|
|||
|
|
<td class="footer-title">Better Thumbnail Browser Documentation
|
|||
|
|
</td>
|
|||
|
|
<td class="footer-copyright">
|
|||
|
|
Copyright © 2010-2012 <a href="../../../index.html" target="_blank">ComponentOwl.com</a>
|
|||
|
|
</td>
|
|||
|
|
</tr></table>
|
|||
|
|
</div></body>
|
|||
|
|
</html>
|