The ThumbnailListView control allows not only working with file system-based items, but also with custom items as well. For example, you can easily create list items which wrap Aurigma.GraphicsMill.Bitmap class instances and display them in the control. This topic describes how to do that.
Graphics Mill for .NET has two interfaces that are implemented by list items:
The IListItem interface exposes a number of methods, events, and properties which are called by the ThumbnailListView control to display thumbnails. Let us look at them more closely.
A large group of members relates to the item state: whether the item is selected, checked, or focused. They are:
Another group of members is responsible for item content. An item can store three kinds of content:
And at last, there is a member that stands apart—the Parent property. It stores a link to the parent ThumbnailListView control.
The IQueueItem interface is optional, but it is strongly recommended to implement it for better usability of your application. If the item implements this interface, the ThumbnailListView control is able to display icons of items asynchronously. In other words, it allows the control to distribute the process of icon and textual data loading in time.
What happens when the control works in a synchronous mode? When an item is added to the control, this item builds four icons to represent itself in four view modes. Typically, this process takes quite a long time. This way, the user interface will freeze until the item icons are built. It may be OK, when few items are added, but if you add hundreds of elements, it becomes unacceptable.
The solution of this problem is an asynchronous mode. An item is added to the control without its icon (a default icon is displayed instead). The item icon is generated in a separate thread. When the icon is ready, the control refreshes and displays the icon for this item.
Now let us see how IQueueItem interface works. It has only three members:
If you implement this interface, you need to force the control to run threads using the QueueManager class (see the code example later).
Now, implement a custom list item which will wrap Aurigma.GraphicsMill.Bitmap objects. Also, this item will hold three text fields: a description of the bitmap (specified in the code), its color space and pixel format (extracted from the Bitmap object).
The IListItem interface contains a lot of members, but fortunately there is no need to implement all of them. Graphics Mill for .NET provides a base implementation of this inteface in the ListItem class. So, just inherit from this class and reuse a larger part of its implementation. The only thing you need to implement is loading of the data into the item, namely:
The best place to do it is the IQueueItem interface, or speaking more precisely, the EvaluateMethod(Int32) method. The only "heavy" operation is icon creation, and therefore this method will implement only one operation, or method in terms of the IQueueItem interface.
The ListItem class has several protected members and one of them will be widely used in the code example below. It is the Texts property. This property is a hash table that keeps all pieces of textual data. The ID of the text string is used as a key of this hash table. When the item is initialized, all pieces of textual information are simply put into this property. If the process of fetching this information takes quite a long time (for example, if it is fetched from a database), you can use the second queue and add appropriate code to the EvaluateMethod(Int32) method.
Take a look at the implementation code:
Public Class BitmapListItem Inherits Aurigma.GraphicsMill.WinControls.ListItem Implements Aurigma.GraphicsMill.WinControls.IQueueItem ' Stores the state of item data loading. Protected _queueMethodState _ As Aurigma.GraphicsMill.WinControls.QueueItemMethodState ' Stores the bitmap represented by this item. Protected _bitmap As Aurigma.GraphicsMill.Bitmap 'Stores the unique key for bitmap thumbnails. Protected _key As Long ' Updates the bitmap represented by this item. Private Sub UpdateBitmap(ByVal bitmap As Aurigma.GraphicsMill.Bitmap) ' Update the bitmap itself. If Not _bitmap Is Nothing Then RemoveHandler _bitmap.Changed, AddressOf _bitmap_Changed End If _bitmap = bitmap ' Subscribe the Changed event so that we could update icons ' if the bitmap is modified outside. AddHandler _bitmap.Changed, AddressOf _bitmap_Changed ' Reset icons. _queueMethodState = _ Aurigma.GraphicsMill.WinControls.QueueItemMethodState.NotStarted ' Update text information which depends on bitmap. UpdateText(TextInfoColorSpaceId, bitmap.ColorSpace.ToString()) UpdateText(TextInfoPixelFormatId, bitmap.PixelFormat.ToString()) ' If the item is already associated with some control, force it to ' update an icon. If Not Parent Is Nothing Then Parent.QueueManager.MoveToHead(Me, 0) Parent.QueueManager.StartQueues() End If End Sub ' Updates text information. Private Sub UpdateText(ByVal textInfoId As Integer, ByVal text As String) Texts(textInfoId) = text OnTextChanged(textInfoId) End Sub ' Changed event handler for the _bitmap. Private Sub _bitmap_Changed(ByVal sender As Object, _ ByVal e As Aurigma.GraphicsMill.BitmapChangedEventArgs) UpdateBitmap(_bitmap) End Sub ' Constructor. Public Sub New(ByVal bitmap As Aurigma.GraphicsMill.Bitmap, _ ByVal description As String) UpdateBitmap(bitmap) UpdateText(TextInfoDescriptionId, description) _key = Id Id = Id + 1 End Sub ' Unique number for item Private Shared Id As Integer = 0 ' Constants of the text data which can be extracted from the item ' (displayed in the Details view mode). It is recommended to use ' values which differs from standard text IDs (used in ThumbnailListItem). Public Const TextInfoDescriptionId As Integer = 10 Public Const TextInfoColorSpaceId As Integer = 11 Public Const TextInfoPixelFormatId As Integer = 12 ' Returns the bitmap represented by this item. Public Property Bitmap() As Aurigma.GraphicsMill.Bitmap Get Return _bitmap End Get Set(ByVal Value As Aurigma.GraphicsMill.Bitmap) UpdateBitmap(Value) End Set End Property ' IQueueItem implementation ' Runs the process of item data extraction. This implementation ' supports only one queue and methodIndex should be always equal to 0. Public Sub EvaluateMethod(ByVal methodIndex As Integer) _ Implements Aurigma.GraphicsMill.WinControls.IQueueItem.EvaluateMethod If methodIndex = 0 Then ' Indicate that method is in process. _queueMethodState = _ Aurigma.GraphicsMill.WinControls.QueueItemMethodState.Started ' Create an icon for Thumbnails view. We will use the resized ' version of the bitmap for this. ' Prepare the Resize object. Dim resize As New Aurigma.GraphicsMill.Transforms.Resize resize.Width = Parent.ThumbnailSize.Width resize.Height = Parent.ThumbnailSize.Height resize.InterpolationMode = _ Aurigma.GraphicsMill.Transforms.InterpolationMode.HighQuality resize.ResizeMode = _ Aurigma.GraphicsMill.Transforms.ResizeMode.Fit ' Apply the resize and return the result to a separate bitmap. Dim thumbnail As New Aurigma.GraphicsMill.Bitmap resize.ApplyTransform(_bitmap, thumbnail) ' Put the icon (thumbnail) to the image list of the control ' and store the icon index. Dim listView As Aurigma.GraphicsMill.WinControls.IImageList listView = Parent.GetImageList( _ Aurigma.GraphicsMill.WinControls.View.Thumbnails) listView.AddImage(thumbnail, _key) OnIconChanged(Aurigma.GraphicsMill.WinControls.View.Thumbnails) ' Create an icon for Icon view. 32x32 version of the ' bitmap will be used. ' Everything is the same as for Thumbnails image list. resize.Width = 32 resize.Height = 32 resize.ApplyTransform(_bitmap, thumbnail) listView = Parent.GetImageList( _ Aurigma.GraphicsMill.WinControls.View.Icons) listView.AddImage(thumbnail, _key) OnIconChanged(Aurigma.GraphicsMill.WinControls.View.Icons) ' Create an icon for List and Details views. 16x16 version ' of the bitmap will be used. ' The same icon will be reused for both view modes. resize.Width = 16 resize.Height = 16 resize.ApplyTransform(_bitmap, thumbnail) listView = Parent.GetImageList( _ Aurigma.GraphicsMill.WinControls.View.List) listView.AddImage(thumbnail, _key) OnIconChanged(Aurigma.GraphicsMill.WinControls.View.List) listView = Parent.GetImageList( _ Aurigma.GraphicsMill.WinControls.View.Details) listView.AddImage(thumbnail, _key) OnIconChanged(Aurigma.GraphicsMill.WinControls.View.Details) ' Indicate that the method has been finished. _queueMethodState = _ Aurigma.GraphicsMill.WinControls.QueueItemMethodState.Finished ' Cleanup thumbnail.Dispose() Else Throw New System.NotImplementedException(Me.GetType().ToString() & _ "class supports only one method queue. Make sure that when " & _ "you call EvaluateMethod method, methodIndex equals to 0. ") End If End Sub ' Returns the current state of the data extraction process. Public Function GetMethodState(ByVal methodIndex As Integer) _ As Aurigma.GraphicsMill.WinControls.QueueItemMethodState _ Implements Aurigma.GraphicsMill.WinControls.IQueueItem.GetMethodState Return _queueMethodState End Function ' Returns a number of supported method queues (currently = 1). Public ReadOnly Property MethodCount() As Integer _ Implements Aurigma.GraphicsMill.WinControls.IQueueItem.MethodCount Get Return 1 End Get End Property ' IListItem interface partial implementation. Just override ' GetIconIndex method which will start bitmap loading if icon ' is not avaialble. All the rest implementation is inherited from ' ListItem class. Public Overrides Function GetIconKey(ByVal view As _ Aurigma.GraphicsMill.WinControls.View) _ As Object If (Not HasIcon(view)) Then ' If no icon available, we need to move the current item ' to the head of the first (and the single) queue and re-start ' queue processing. Parent.QueueManager.MoveToHead(Me, 0) Parent.QueueManager.StartQueues() ' Indicate that the icon is not available yet. Return Nothing Else ' If icon is available, just return it. Return _key End If End Function Public Overrides Function HasIcon(ByVal view As _ Aurigma.GraphicsMill.WinControls.View) As Boolean Return Parent.GetImageList(view).ContainsKey(_key) End Function End Class
public class BitmapListItem: Aurigma.GraphicsMill.WinControls.ListItem, Aurigma.GraphicsMill.WinControls.IQueueItem { // Stores the state of item data loading. protected Aurigma.GraphicsMill.WinControls.QueueItemMethodState _queueMethodState; // Stores the bitmap represented by this item. protected Aurigma.GraphicsMill.Bitmap _bitmap; // Stores the unique key for bitmap thumbnails. protected long _key; // Updates the bitmap represented by this item. private void UpdateBitmap(Aurigma.GraphicsMill.Bitmap bitmap) { // Update the bitmap itself. if (_bitmap != null) { _bitmap.Changed -= new Aurigma.GraphicsMill.BitmapChangedEventHandler( _bitmap_Changed); } _bitmap = bitmap; // Subscribe the Changed event so that we could update icons // if the bitmap is modified outside. _bitmap.Changed += new Aurigma.GraphicsMill.BitmapChangedEventHandler( _bitmap_Changed); // Reset icons. _queueMethodState = Aurigma.GraphicsMill.WinControls.QueueItemMethodState.NotStarted; // Update text information which depends on bitmap. UpdateText(TextInfoColorSpaceId, bitmap.ColorSpace.ToString()); UpdateText(TextInfoPixelFormatId, bitmap.PixelFormat.ToString()); // If the item is already associated with some control, force it to // update an icon. if (Parent != null) { Parent.QueueManager.MoveToHead(this, 0); Parent.QueueManager.StartQueues(); } } // Updates text information. private void UpdateText(int textInfoId, string text) { Texts[textInfoId] = text; OnTextChanged(textInfoId); } // Changed event handler for the _bitmap. private void _bitmap_Changed(object sender, Aurigma.GraphicsMill.BitmapChangedEventArgs e) { UpdateBitmap(_bitmap); } // Constructor. public BitmapListItem(Aurigma.GraphicsMill.Bitmap bitmap, string description) { UpdateBitmap(bitmap); UpdateText(TextInfoDescriptionId, description); _key = Id++; } // Unique number for item private static int Id = 0; // Constants of the text data which can be extracted from the item // (displayed in the Details view mode). It is recommended to use // values which differs from standard text IDs (used in ThumbnailListItem). public const int TextInfoDescriptionId = 10; public const int TextInfoColorSpaceId = 11; public const int TextInfoPixelFormatId = 12; // Returns the bitmap represented by this item. public Aurigma.GraphicsMill.Bitmap Bitmap { get { return _bitmap; } set { UpdateBitmap(value); } } // IQueueItem implementation // Runs the process of item data extraction. This implementation // supports only one queue and methodIndex should be always equal to 0. public void EvaluateMethod(int methodIndex) { if (methodIndex == 0) { // Indicate that method is in process. _queueMethodState = Aurigma.GraphicsMill.WinControls.QueueItemMethodState.Started; // Create an icon for Thumbnails view. We will use the resized // version of the bitmap for this. // Prepare the Resize object. Aurigma.GraphicsMill.Transforms.Resize resize = new Aurigma.GraphicsMill.Transforms.Resize(); resize.Width = Parent.ThumbnailSize.Width; resize.Height = Parent.ThumbnailSize.Height; resize.InterpolationMode = Aurigma.GraphicsMill.Transforms.InterpolationMode.HighQuality; resize.ResizeMode = Aurigma.GraphicsMill.Transforms.ResizeMode.Fit; // Apply the resize and return the result to a separate bitmap. Aurigma.GraphicsMill.Bitmap thumbnail = new Aurigma.GraphicsMill.Bitmap(); resize.ApplyTransform(_bitmap, thumbnail); // Put the icon (thumbnail) to the image list of the control // and store the icon index. Aurigma.GraphicsMill.WinControls.IImageList listView = Parent.GetImageList( Aurigma.GraphicsMill.WinControls.View.Thumbnails); listView.AddImage(thumbnail, _key); OnIconChanged(Aurigma.GraphicsMill.WinControls.View.Thumbnails); // Create an icon for Icon view. 32x32 version of the bitmap // will be used. // Everything is the same as for Thumbnails image list. resize.Width = 32; resize.Height = 32; resize.ApplyTransform(_bitmap, thumbnail); listView = Parent.GetImageList( Aurigma.GraphicsMill.WinControls.View.Icons); listView.AddImage(thumbnail, _key); OnIconChanged(Aurigma.GraphicsMill.WinControls.View.Icons); // Create an icon for List and Details views. 16x16 version of // the bitmap will be used. // The same icon will be reused for both view modes. resize.Width = 16; resize.Height = 16; resize.ApplyTransform(_bitmap, thumbnail); listView = Parent.GetImageList( Aurigma.GraphicsMill.WinControls.View.List); listView.AddImage(thumbnail, _key); OnIconChanged(Aurigma.GraphicsMill.WinControls.View.List); listView = Parent.GetImageList( Aurigma.GraphicsMill.WinControls.View.Details); listView.AddImage(thumbnail, _key); OnIconChanged(Aurigma.GraphicsMill.WinControls.View.Details); // Indicate that the method has been finished. _queueMethodState = Aurigma.GraphicsMill.WinControls.QueueItemMethodState.Finished; // Cleanup. thumbnail.Dispose(); } else { throw new System.NotImplementedException(this.GetType().ToString() + "class supports only one method queue. Make sure that when " + "you call EvaluateMethod method, methodIndex equals to 0. "); } } // Returns the current state of the data extraction process. public Aurigma.GraphicsMill.WinControls.QueueItemMethodState GetMethodState(int methodIndex) { return _queueMethodState; } // Returns a number of supported method queues (currently = 1). public int MethodCount { get { return 1; } } // IListItem interface partial implementation. Just override // GetIconKey method which will start bitmap loading if icon // is not avaialble. All the rest implementation is inherited from // ListItem class. public override object GetIconKey( Aurigma.GraphicsMill.WinControls.View view) { if (!HasIcon(view)) { // If no icon available, we need to move the current item // to the head of the first (and the single) queue and re-start // queue processing. Parent.QueueManager.MoveToHead(this, 0); Parent.QueueManager.StartQueues(); // Indicate that the icon is not available yet. return null; } else { // If icon is available, just return the key. return _key; } } public override bool HasIcon(Aurigma.GraphicsMill.WinControls.View view) { return Parent.GetImageList(view).ContainsKey(_key); } }
The usage of this class is very similar to the one of ThumbnailListItem. Here is how items are added to the control and how the columns are configured for the detals list.
Dim item1 As BitmapListItem, item2 As BitmapListItem ' This item represents a bitmap object loaded from file. item1 = New BitmapListItem( _ New Aurigma.GraphicsMill.Bitmap("C:\[Test Files]\mk-319.jpg"), _ "Microphone photo loaded from file") ' This item represents a bitmap object created from a scratch. ' Here we create grayscale bitmap and draw an ellipse. item2 = New BitmapListItem( _ New Aurigma.GraphicsMill.Bitmap(Aurigma.GraphicsMill.RgbColor.Aqua, _ 320, 240, _ Aurigma.GraphicsMill.PixelFormat.Format8bppGrayScale, _ Nothing), _ "Self-created bitmap") Dim graphics As Aurigma.GraphicsMill.Drawing.GdiGraphics = _ item2.Bitmap.GetGdiGraphics() graphics.FillEllipse(New Aurigma.GraphicsMill.Drawing.SolidBrush, _ 50, 50, 200, 150) graphics.Dispose() ' Put items to the control. ThumbnailListView1.Items.Add(item1) ThumbnailListView1.Items.Add(item2) ' Configure columns for the Details view and caption for other views. ThumbnailListView1.Columns.Add( _ New Aurigma.GraphicsMill.WinControls.ListColumn( _ BitmapListItem.TextInfoDescriptionId, _ "Description", 200, _ System.Windows.Forms.HorizontalAlignment.Left)) ThumbnailListView1.Columns.Add( _ New Aurigma.GraphicsMill.WinControls.ListColumn( _ BitmapListItem.TextInfoColorSpaceId, _ "Color Space", 100, _ System.Windows.Forms.HorizontalAlignment.Left)) ThumbnailListView1.Columns.Add( _ New Aurigma.GraphicsMill.WinControls.ListColumn( _ BitmapListItem.TextInfoPixelFormatId, _ "Pixel Format", 150, _ System.Windows.Forms.HorizontalAlignment.Left)) ThumbnailListView1.IconicViewTextInfoId = _ BitmapListItem.TextInfoDescriptionId
BitmapListItem item1, item2; // This item represents a bitmap object loaded from file. item1 = new BitmapListItem( new Aurigma.GraphicsMill.Bitmap(@"C:\[Test Files]\mk-319.jpg"), "Microphone photo loaded from file"); // This item represents a bitmap object created from a scratch. // Here we create grayscale bitmap and draw an ellipse. item2 = new BitmapListItem( new Aurigma.GraphicsMill.Bitmap(Aurigma.GraphicsMill.RgbColor.Aqua, 320, 240, Aurigma.GraphicsMill.PixelFormat.Format8bppGrayScale, null), "Self-created bitmap"); Aurigma.GraphicsMill.Drawing.GdiGraphics graphics = item2.Bitmap.GetGdiGraphics(); graphics.FillEllipse(new Aurigma.GraphicsMill.Drawing.SolidBrush(), 50, 50, 200, 150); graphics.Dispose(); // Put items to the control. thumbnailListView1.Items.Add(item1); thumbnailListView1.Items.Add(item2); // Configure columns for the Details view and caption for other views. thumbnailListView1.Columns.Add( new Aurigma.GraphicsMill.WinControls.ListColumn( BitmapListItem.TextInfoDescriptionId, "Description", 200, System.Windows.Forms.HorizontalAlignment.Left)); thumbnailListView1.Columns.Add( new Aurigma.GraphicsMill.WinControls.ListColumn( BitmapListItem.TextInfoColorSpaceId, "Color Space", 100, System.Windows.Forms.HorizontalAlignment.Left)); thumbnailListView1.Columns.Add( new Aurigma.GraphicsMill.WinControls.ListColumn( BitmapListItem.TextInfoPixelFormatId, "Pixel Format", 150, System.Windows.Forms.HorizontalAlignment.Left)); thumbnailListView1.IconicViewTextInfoId = BitmapListItem.TextInfoDescriptionId;
As a result, your bitmaps will be displayed in the control as follows:
View = Thumbnails
|
View = Icons
|
View = List
|
View = Details
|