Contents
Introduction
Windows XP style Explorer Bars/Task Bars/Web Views - call them what you will - are all the rage at the moment. There are many great free Explorer Bar controls available on the net such as Derek Lakin's Collapsible Panel Bar, Darren May's Collapsing Group Control, and Tom Guinther's Full-featured XP Style Collapsible Panel. Most of them don't support Windows XP themes, or if they do, they "fake" it by drawing the gradient/arrows themselves, or by including the necessary images in the assembly.
Frustrated by this lack of proper theme support, I decided to make my own.
Features
- Windows XP theme support - even on pre XP versions
- Animated expand/collapse with fade effect
- Animated show/hide of items with slide effect
- Automatic layout of all groups and their items
- Groups can start collapsed or expanded
- Group re-ordering (including at design time)
- Focus and keyboard navigation similar to Windows XP's Explorer Bar
- User defined settings - gradients, colors, borders and more
- Supports .NET Framework versions 1.0 and 1.1
- Supports Binary and XML Serialization
Themes
So, how can we make use of themes?
My first attempt was to take screenshots of the real Explorer Bar in action so I could get the images and colors that I would need. This worked well as long as I only used the Luna themes that come with XP. I was forced to go back to the drawing board.
After stumbling across Don Kackman's article on Adding XP Themes to Custom .NET Controls, attempt #2 was to make use of UxTheme.dll. That was until I got to the part where using UxTheme worked as long as you only used the default Blue Luna theme. However, Don came up with a potential solution - get the necessary information from ShellStyle.dll.
ShellStyle.dll
Now that I knew where to look, the question was "what am I looking for?" TGTSoft (the makers of StyleXP) have a great free program called ResBuilder that allows you to open and modify Windows resource files. Armed with this program, I was able to have a poke around inside ShellStyle.dll.
Figure 1: ShellStyle.dll in ResBuilder
The sections I needed were the Bitmap
(obviously) and the UIFILE
- more on these later.
Before loading the ShellStyle.dll, we need to check whether themes are available:
if (UxTheme.AppThemed && LoadShellStyleDll())
{
...
If they are available, then go ahead and load the ShellStyle.dll:
private static bool LoadShellStyleDll()
{
string themeName = UxTheme.ThemeName.Substring(0,
UxTheme.ThemeName.LastIndexOf('\\'));
string styleName = themeName + "\\Shell\\" + UxTheme.ColorName;
string stylePath = styleName + "\\shellstyle.dll";
// if for some reason it doesn't exist, use the default
// shellstyle.dll in the windows\system32 directory
if (!File.Exists(stylePath))
{
stylePath = Environment.GetFolderPath(Environment.SpecialFolder.System) +
"\\shellstyle.dll";
}
// attempt to load the shellstyle dll
hModule = LoadLibrary(stylePath);
// return whether we succeeded
return (hModule != IntPtr.Zero);
}
The UIFILE
So, what is a UIFILE? The UIFILE is basically a style sheet that tells the Explorer Bar how it should render itself. Below is a small section that shows settings for a special group's titlebar for the Blue Luna theme:
button [id=atom(header)]
{
background: rcbmp(110,6,#FF00FF,0,0,1,0);
borderthickness: rect(2,2,2,0);
foreground: white;
fontweight: rcint(10);
padding: rect(10,0,0,0);
animation: rectanglev | s | fast;
}
(For more information on UIFILEs, bfarber.com has a tutorial on how to read a UIFILE).
You'll notice that there are two UIFILEs - the first one is for the Explorer Bar, and the second is for the Control Panel. Now that we know which one we want, it is time to read its contents:
public static string GetResourceUIFile()
{
IntPtr hResource = FindResource(hModule, "#1", "UIFILE");
int resourceSize = SizeofResource(hModule, hResource);
IntPtr resourceData = LoadResource(hModule, hResource);
byte[] uiBytes = new byte[resourceSize];
GCHandle gcHandle = GCHandle.Alloc(uiBytes, GCHandleType.Pinned);
IntPtr firstCopyElement = Marshal.UnsafeAddrOfPinnedArrayElement(uiBytes, 0);
CopyMemory(firstCopyElement, resourceData, resourceSize);
gcHandle.Free();
FreeResource(resourceData);
string s = Marshal.PtrToStringAnsi(firstCopyElement, resourceSize);
return s;
}
Extracting Bitmaps
All bitmaps in the UIFILE have the following format:
rcbmp(id, stretching, transparency, width, height, size, mirror)
To load a bitmap, we just pass the bitmap ID to the GetResourceBMP
method:
public static Bitmap GetResourceBMP(string resourceName)
{
IntPtr hBitmap = LoadBitmap(hModule, Int32.Parse(resourceName));
Bitmap bitmap = Bitmap.FromHbitmap(hBitmap);
return bitmap;
}
The method above works for ordinary bitmaps, but we run into a major problem if the image is a 32bpp PNG - the alpha channel is lost, leaving black areas where the transparency should be.
Figure 2: Alpha channel comparison
The following solution to this problem was posted on Derek Lakin's blog:
public static Bitmap GetResourcePNG(string resourceName)
{
const int FILE_HEADER_BYTES = 40;
Bitmap tmpNoAlpha = Bitmap.FromResource(hModule, "#" + resourceName);
IntPtr hResource = FindResource(hModule, "#" + resourceName,
(IntPtr) 2 );
int resourceSize = SizeofResource(hModule, hResource);
Bitmap bitmap = new Bitmap(tmpNoAlpha.Width,
tmpNoAlpha.Height,
PixelFormat.Format32bppArgb);
IntPtr hLoadedResource = LoadResource(hModule, hResource);
byte[] bitmapBytes = new byte[resourceSize];
GCHandle gcHandle = GCHandle.Alloc(bitmapBytes, GCHandleType.Pinned);
IntPtr firstCopyElement =
Marshal.UnsafeAddrOfPinnedArrayElement(bitmapBytes, 0);
CopyMemory(firstCopyElement, hLoadedResource, resourceSize);
FreeResource(hLoadedResource);
Rectangle copyArea = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
BitmapData alphaBits = bitmap.LockBits(copyArea,
ImageLockMode.WriteOnly,
PixelFormat.Format32bppArgb);
firstCopyElement = Marshal.UnsafeAddrOfPinnedArrayElement(bitmapBytes,
FILE_HEADER_BYTES);
CopyMemory(alphaBits.Scan0, firstCopyElement,
resourceSize - FILE_HEADER_BYTES);
gcHandle.Free();
bitmap.UnlockBits(alphaBits);
GdiFlush();
bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);
return bitmap;
}
So, how do we know which one to use for each image? Generally speaking, normal bitmaps will use a hexadecimal transparency value, while PNGs will use an integer value.
...
if (transparent.StartsWith("#"))
{
image = Util.GetResourceBMP(id);
...
}
else
{
image = Util.GetResourcePNG(id);
}
...
XPExplorerBar
The XPExplorerBar
consists of three main components:
- The
TaskPane
Expando
s, and
TaskItem
s
I won't go into great detail about how each of these were implemented as that is what the source code is for, but I will give an insight into some of the more interesting features such as animation.
Using XPExplorerBar
Before using the XPExplorerBar
, you need to add a reference to XPExplorerBar.dll in the References section of your project.
To add the XPExplorerBar.dll to the toolbox, you can either:
- Select Tools -> Add/Remove Toolbox Items from the menu, or
- Right click on the toolbox, select Add/Remove Items.
and browse for XPExplorerBar.dll and then press OK. You can then drag the controls onto your Form.
Note: If you recompile the source code you will need to re-sign XPExplorerBar.dll, as otherwise Visual Studio will throw an exception when you attempt to add it to the toolbox.
- Open up the VS.NET command prompt and change the directory to point to the XPExplorerBar\bin\Release directory.
- Then type "sn -R XPExplorerBar.dll ..\..\XPExplorerBar.snk" (without the quotes of course).
You should then be able to add it to the toolbox.
TaskPane
The TaskPane
acts as a container for all the Expando
s that the XPExplorerBar
will contain.
Expandos
An ExpandoCollection
representing the collection of Expando
s contained within the TaskPane
.
CustomSettings
The custom settings used to draw the TaskPane
.
Note: Changing one of these settings will override the same system setting defined in a shellstyle.dll.
Adding Expandos to a TaskPane
There are two ways to add Expando
s to a TaskPane
:
- Via the
Expandos
property in the property editor window, or
- Dragging
Expando
s from the toolbox onto a TaskPane
Figure 3: Adding Expandos with the property editor
Reordering Expandos
During design time, you can use the up and down arrow buttons in the Expando Collection Editor to reorder the Expando
s.
Figure 4: Use arrow buttons to reorder Expandos at design time
At all other times, the TaskPane
's Expandos
property provides the following methods to reorder Expando
s:
Move(Expando value, int index)
Moves the specified Expando
to the specified indexed location in the ExpandoCollection
.
MoveToTop(Expando value)
Moves the specified Expando
to the top of the ExpandoCollection
.
MoveToBottom(Expando value)
Moves the specified Expando
to the bottom of the ExpandoCollection
.
taskpane.Expandos.MoveToTop(expando);
Using Themes Other Than The Current Theme
The XPExplorerBar
also allows you to use themes that are different to the current theme.
UseClassicTheme()
Forces the TaskPane
and all its Expando
s to use a theme equivalent to Windows XP's Classic Theme (this is the default theme on Windows 2000 or earlier).
UseCustomTheme(string stylePath)
Forces the TaskPane
and all its Expando
s to use the specified theme.
UseDefaultTheme()
Forces the TaskPane
and all its Expando
s to use the current system theme.
UseClassicTheme()
and UseDefaultTheme()
will appear to do the same thing on Windows versions prior to XP, or on XP machines with themes disabled. Note that UseCustomTheme()
will work on Windows 2000 or earlier.
TaskPane taskpane = new TaskPane();
taskpane.UseCustomTheme("foreverblue.dll");
Figure 5: XPExplorerBar demo with Windows XP theme Forever Blue on Windows 2000
Custom themes can be found at ThemeXP.
Collapsing/Expanding Multiple Expandos
The XPExplorerBar
now allows you to expand or collapse multiple Expando
s at the same time.
CollapseAll()
Collapses all the Expando
s contained in the TaskPane
.
ExpandAll()
Expands all the Expando
s contained in the TaskPane
.
CollapseAllButOne(Expando expando)
Collapses all the Expando
s contained in the TaskPane
, except for the specified Expando
which is expanded.
Expando
Expando
s are containers for TaskItem
s and other Control
s, and can be collapsed/expanded as necessary. Note that Expando
s will only animate if they are added to a TaskPane
.
I'm sure that right about now, you're wondering where I got the name Expando
from. If you look at the UIFILE, you will get an idea (it's the name Microsoft has given the collapsible group).
Animate
Determines whether the Expando
will perform collapse/expand or show/hide animations.
AutoLayout
Determines whether the Expando
will automagically layout its items.
Collapsed
Determines whether the Expando
is collapsed or expanded.
CustomSettings
The custom settings used to draw the Expando
's body.
Note: Changing one of these settings will override the same system setting defined in a shellstyle.dll.
CustomHeaderSettings
The custom settings used to draw the Expando
's title bar.
Note: Changing one of these settings will override the same system setting defined in a shellstyle.dll.
ExpandedHeight
Sets the height of the Expando
in its expanded state. This is ignored if the AutoLayout
property is used.
Items
An ItemCollection
representing the collection of Control
s contained within the Expando
.
ShowFocusCues
Gets or sets a value indicating whether the Expando
should display focus rectangles when it has focus.
SpecialGroup
Determines whether the Expando
will be rendered as a Special Group.
TitleImage
Specifies the Image
that is displayed on the left side of the Expando
's titlebar.
Adding Controls to an Expando
There are two ways to add Control
s to an Expando
:
- Via the
Items
property in the property editor window, or
- Dragging
Control
s from the toolbox onto an Expando
.
Figure 6a (top) and 6b (bottom): Adding Controls with the property editor.
Version 3.0 now allows other Control
s besides TaskItem
s to be added via the Items
property in the designer. Clicking the Add button will add a TaskItem
to the Expando
, while clicking the arrow next to the Add button will provide a list of the more useful Control
s to add to the Expando
.
Reordering Controls
During design time, you can use the up and down arrow buttons in the Control Collection Editor to reorder the Control
s.
Figure 7: Use arrow buttons to reorder Controls at design time
At all other times, the Expando
's Items
property provides the following methods to reorder Control
s:
Move(Control value, int index)
Moves the specified Control
to the specified indexed location in the ItemCollection
.
MoveToTop(Control value)
Moves the specified Control
to the top of the ItemCollection
.
MoveToBottom(Control value)
Moves the specified Control
to the bottom of the ItemCollection
.
expando.Items.MoveToTop(taskitem);
As of v3.3 Expando
s can now be dragged around a TaskPane
. For this to happen the TaskPane
's AllowExpandoDragging
property should be set to true
.
Figure 8: Dragging Expandos around a TaskPane
Hide/Show Controls
In order to hide or show items, the HideControl
and ShowControl
methods have been provided. You shouldn't use control.Visible = false
to hide items, as the Expando
will need to make the control visible again in order to perform an expand animation without any visual artifacts (such as a black background for some themed controls), most likely causing the control to stay visible when it should be hidden, as well as cause a few layout headaches.
HideControl(Control control)
Hides the specified Control
.
HideControl(Control[] controls)
Hides the specified array of Control
s.
ShowControl(Control control)
Shows the specified Control
.
ShowControl(Control[] controls)
Shows the specified array of Control
s.
Note: In order for the Expando
to perform an animation, the Expando
's AutoLayout
and Animate
properties must all be true
.
Note: As of version 3.3 you can batch HideControl
/ ShowControl
commands using the BeginUpdate()
/ EndUpdate()
methods:
expando.BeginUpdate();
expando.HideControl(new Control[] {taskItem1, taskItem2});
expando.ShowControl(taskItem3);
expando.EndUpdate();
Note: At the moment the BeginUpdate()
/EndUpdate()
methods are only useful for this purpose.
Docking and Scrolling
Figure 9: A docked scrollable Panel
As of version 3.0, Expando
s no longer support scrolling. The way that scrolling was implemented in version 2.x caused a few rendering problems that I have yet to resolve. Hopefully by removing scroll support in this version I will have more time to fix the problems, and add scrolling support back in a future version (as opposed to delaying releases). Apologies for any inconvenience this may cause.
To add scrolling, simply add a scrollable Panel
and set its DockStyle
property to Fill
.
To stop child controls from covering the title bar and borders when docked, I overrode the Expando
's DisplayRectangle
property.
public override Rectangle DisplayRectangle
{
get
{
return new Rectangle(this.Border.Left,
this.HeaderHeight + this.Border.Top,
this.Width - this.Border.Left - this.Border.Right,
this.ExpandedHeight - this.HeaderHeight -
this.Border.Top - this.Border.Bottom);
}
}
Animation
Figure 10: Animated collapse in action
To enable collapse/expand animation, the Expando
's Animate
property must be set to true
:
public bool Animate
{
get
{
return this.animate;
}
set
{
this.animate = value;
}
}
When the Expando
's Collapsed
property changes, it checks whether it can animate.
public bool Collapsed
{
...
set
{
if (this.collapsed != value)
{
if (value && !this.CanCollapse)
{
return;
}
this.collapsed = value;
if (this.Animate && !this.DesignMode && !this.Initialising)
{
...
If the Expando
is able to animate, it creates a new AnimationHelper
that tells the Expando
to get ready and starts the animation timer.
...
this.animationHelper = new AnimationHelper(this,
AnimationHelper.FadeAnimation);
this.OnStateChanged(new ExpandoEventArgs(this));
this.animationHelper.StartAnimation();
...
}
}
}
}
protected void StartAnimation()
{
if (this.Animating)
{
return;
}
this.animationStepNum = 0;
if (this.AnimationType == FadeAnimation)
{
this.expando.StartFadeAnimation();
}
else
{
this.expando.StartSlideAnimation();
}
this.animationTimer.Start();
}
Once the Expando
receives the StartAnimation
message, it takes a "snap-shot" of its "client area" (i.e., its dockable area). All the Expando
's child controls are set invisible as otherwise they would appear to slide off the bottom of the Expando
(also controls that have their FlatStyle
property set to System
don't like having their opacity changed).
protected void StartAnimation()
{
this.animating = true;
this.SuspendLayout();
this.animationImage = this.GetAnimationImage();
foreach (Control control in this.Controls)
{
control.Visible = false;
}
this.ResumeLayout(false);
}
internal Image GetAnimationImage()
{
Image image = new Bitmap(this.Width, this.Height);
Graphics g = Graphics.FromImage(image);
IntPtr hDC = g.GetHdc();
IntPtr flags = (IntPtr) (WmPrintFlags.PRF_CLIENT |
WmPrintFlags.PRF_CHILDREN |
WmPrintFlags.PRF_ERASEBKGND);
NativeMethods.SendMessage(this.Handle,
WindowMessageFlags.WM_PRINT,
hDC, flags);
g.ReleaseHdc(hDC);
g.Dispose();
return image;
}
[DllImport("User32.dll")]
internal static extern int SendMessage(IntPtr hwnd,
int msg,
IntPtr wParam,
IntPtr lParam);
The animationImage
is faded and moved up/down as necessary during the animation.
protected void PaintDisplayRect(Graphics g)
{
if (this.animating && this.animationImage != null)
{
float alpha = (((float) (this.Height - this.HeaderHeight)) /
((float) (this.ExpandedHeight - this.HeaderHeight)));
float[][] ptsArray = {new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, alpha, 0},
new float[] {0, 0, 0, 0, 1}};
ColorMatrix colorMatrix = new ColorMatrix(ptsArray);
ImageAttributes imageAttributes = new ImageAttributes();
imageAttributes.SetColorMatrix(colorMatrix,
ColorMatrixFlag.Default,
ColorAdjustType.Bitmap);
int y = this.animationImage.Height - this.PseudoClientHeight
- this.Border.Bottom;
g.DrawImage(this.animationImage,
new Rectangle(0, this.HeaderHeight, this.Width,
this.Height - this.HeaderHeight),
0,
y,
this.animationImage.Width,
this.animationImage.Height - y,
GraphicsUnit.Pixel,
imageAttributes);
}
else
{
...
}
}
TaskItem
Figure 11: A TaskItem
TaskItem
s are similar to Label
s. Each TaskItem
can contain an Image
that is restricted to 16x16 pixels. Larger or smaller images can be used, but they will be enlarged/decreased to 16x16 as necessary.
CustomSettings
The custom settings used to draw the TaskItem
.
Note: Changing one of these settings will override the same system setting defined in a shellstyle.dll.
Image
The image that is displayed on a TaskItem
.
ShowFocusCues
Gets or sets a value indicating whether the TaskItem
should display focus rectangles when it has focus.
Points of Interest
Serialization
As of v3.2, Binary Serialization support has been reworked and XML Serialization support has been added.
Note: v3.2.1 adds a Version property to the serialization process to ensure backward compatibility with future versions. Anyone using serialization is encouraged to upgrade to v3.2.1
In order to fix the problems that v3.1 had with serialization, I needed to find a new way to perform serialization. After much Googling, I came across the concept of surrogates. A surrogate is a class that will be serialized in place of another class (usually because the other class is either not serializable or contains classes that are not serializable or cause serialization problems).
TaskPane.TaskPaneSurrogate
A class that is serialized instead of a TaskPane
.
Expando.ExpandoSurrogate
A class that is serialized instead of an Expando
.
TaskItem.TaskItemSurrogate
A class that is serialized instead of a TaskItem
.
All the above Surrogates have the following methods for importing/exporting data to/from a Surrogate:
The example below shows how a TaskPane
can be serialized and deserialized by a TaskPane.TaskPaneSurrogate
with Binary and XML serialization:
IFormatter formatter = new BinaryFormatter();
stream = new FileStream("TaskPane.bin", FileMode.Create, FileAccess.Write,
FileShare.None);
TaskPane.TaskPaneSurrogate taskPaneSurrogate =
new TaskPane.TaskPaneSurrogate();
taskPaneSurrogate.Load(this.serializeTaskPane);
formatter.Serialize(stream, taskPaneSurrogate);
stream.Close();
IFormatter formatter = new BinaryFormatter();
stream = new FileStream("TaskPane.bin", FileMode.Open, FileAccess.Read,
FileShare.Read);
TaskPane.TaskPaneSurrogate taskPaneSurrogate =
(TaskPane.TaskPaneSurrogate) formatter.Deserialize(stream);
TaskPane taskpane = taskPaneSurrogate.Save();
stream.Close();
XmlSerializer xml = new XmlSerializer(typeof(TaskPane.TaskPaneSurrogate));
StreamWriter writer = new StreamWriter("TaskPane.xml");
TaskPane.TaskPaneSurrogate taskPaneSurrogate =
new TaskPane.TaskPaneSurrogate();
taskPaneSurrogate.Load(this.serializeTaskPane);
xml.Serialize(writer, taskPaneSurrogate);
writer.Close();
XmlSerializer xml = new XmlSerializer(typeof(TaskPane.TaskPaneSurrogate));
TextReader reader = new StreamReader("TaskPane.xml");
TaskPane.TaskPaneSurrogate taskPaneSurrogate =
(TaskPane.TaskPaneSurrogate) xml.Deserialize(reader);
TaskPane taskpane = taskPaneSurrogate.Save();
reader.Close();
Note: Controls in the Expando.ItemCollection
that are not TaskItem
s are ignored during the serialization process as (unfortunately) they do not support serialization.
Visual Styles and WM_PRINT
Update: I sent a bug report to Microsoft about visual styles and WM_PRINT
messages (which can be found here[^]) and their response was basically that it would be too hard to fix, so it looks like we're stuck with this workaround until Avalon is released.
Some XP themed controls (TextBox
, ListView
, TreeView
, ListBox
, CheckedListBox
, DateTimePicker
, GroupBox
) don't draw a themed border when sent a WM_PRINT
message, if Visual Styles are enabled.
Figure 12: TextBox border after WM_PRINT
message
In order to solve this problem, I immediately ran into another problem - How to find out if Visual Styles are applied (i.e., a manifest or Application.EnableVisualStyles()
is being used). After some Googling, I found this solution which checks if themes are enabled and which version of the Common Controls is being used:
protected bool VisualStylesEnabled
{
get
{
OperatingSystem os = System.Environment.OSVersion;
if (os.Platform == PlatformID.Win32NT &&
((os.Version.Major == 5 && os.Version.Minor >= 1) ||
os.Version.Major > 5))
{
if (UxTheme.IsThemeActive() && UxTheme.IsAppThemed())
{
DLLVERSIONINFO version = new DLLVERSIONINFO();
version.cbSize = Marshal.SizeOf(typeof(DLLVERSIONINFO));
if (DllGetVersion(ref version) == 0)
{
return (version.dwMajorVersion > 5);
}
}
}
return false;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct DLLVERSIONINFO
{
public int cbSize;
public int dwMajorVersion;
public int dwMinorVersion;
public int dwBuildNumber;
public int dwPlatformID;
}
[DllImport("Comctl32.dll")]
public static extern int DllGetVersion(ref DLLVERSIONINFO pdvi);
I then subclassed the offending controls and listened for WM_PRINT
messages, and drew themed borders over the top of the unthemed borders, if Visual Styles are enabled.
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (!this.visualStylesEnabled)
{
return;
}
if (m.Msg == (int) WindowMessageFlags.WM_PRINT)
{
if ((m.LParam.ToInt32() & (int) WmPrintFlags.PRF_NONCLIENT) ==
(int) WmPrintFlags.PRF_NONCLIENT)
{
IntPtr hTheme = UxTheme.OpenThemeData(this.Handle,
UxTheme.WindowClasses.Edit);
if (hTheme != IntPtr.Zero)
{
int partId = (int) UxTheme.Parts.Edit.EditText;
int stateId = (int) UxTheme.PartStates.EditText.Normal;
RECT rect = new RECT();
rect.right = this.Width;
rect.bottom = this.Height;
RECT clipRect = new RECT();
clipRect.left = rect.left;
clipRect.top = rect.top;
clipRect.right = rect.left + 2;
clipRect.bottom = rect.bottom;
UxTheme.DrawThemeBackground(hTheme, m.WParam, partId, stateId,
ref rect, ref clipRect);
...
}
UxTheme.CloseThemeData(hTheme);
}
}
}
The subclassed controls (XPTextBox
, XPListView
, XPTreeView
, XPListBox
, XPCheckedListBox
, XPDateTimePicker
) are included in the download.
Known Problems
XPExplorerBar
may not correctly render non-official XP themes.
History
- 30 September 2005 - Version 3.3
- Added
RightToLeft
support for Expando
s and TaskItem
s.
- Added ability to batch
HideControl
/ShowControl
commands for Expando
s (see Hide/Show Controls for more details).
- Added ability for
Expando
s to be dragged around a TaskPane
.
- Fixed
TaskItem
's text is sometimes clipped.
- Other bug fixes.
- 24 February 2005 - Version 3.2.1.2
- Fixed
Expando
Hide/ShowControl methods trying to animate while Expando
is collapsed.
- Changed
UseDefaultTabHandling
property so that the default focus and keyboard navigation is enabled by default. To use tab handling similar to Windows XP's Explorer Bar UseDefaultTabHandling
must be explicitly set to false
.
- 17 February 2005 - Version 3.2.1.1
- Removed excess
Serializable
attributes from classes which shouldn't be serialized.
- Added
UseDefaultTabHandling
property to Expando
s so the user can choose the default focus and keyboard navigation or use focus and keyboard navigation similar to Windows XP's Explorer Bar.
- 22 January 2005 - Version 3.2.1
- Added Version property for serialization to ensure backward compatibility with future versions.
- Other bug fixes.
- 19 January 2005 - Version 3.2
- Changed the way Binary Serialization works and added XML serialization support.
- Fixed can't extract images from shellstyle.dlls on Windows 9x bug.
- Fixed "Resource transformation for file 'Myfile.resx' failed" bug.
- Improved theme support.
- Other bug fixes.
- 2 November 2004 - Version 3.1
- Added Binary Serialization support for
TaskPane
s, Expando
s, TaskItem
s, TaskPane.ExpandoCollection
s and Expando.ItemCollection
s.
- Fixed can't add
TaskItem
s or other controls to Expando
s programmatically bug which was accidentally reintroduced in v3.0.
- Other bug fixes.
- 25 October 2004 - Version 3.0
- Added custom settings for
TaskPane
s, Expando
s and TaskItem
s.
- Removed native scrolling support for
Expando
s due to rendering issues.
- Fixed
Expando
s start at point (0, 0) when added to a TaskPane
programmatically bug.
- Fixed
Expando
s start with incorrect height if Collapsed
and have a TitleImage
bug.
- Other bug fixes
- 11 October 2004 - Version 2.1
- Changed
Expando
s so that collapse/expand arrows and titlebar highlights are not displayed when the CanCollapse
property is false
.
- 30 September 2004 - Version 2.0
- Added native scrolling support for
Expando
s.
- Added focus and keyboard navigation similar to Windows XP's Explorer Bar.
- Fixed bug: can't add
Expando
s, TaskItem
s or other controls programmatically.
- 3 September 2004 - Version 1.4
- Added
Control
re-ordering on Expando
s.
- 26 August 2004 - Version 1.3
- Added
Expando
re-ordering.
- 21 August 2004 - Version 1.21
Expando
s titlebar now rendered in grayscale when disabled.
TaskItem
s render their text the same as a Label
when disabled.
- Improved theme support.
- 5 August 2004 - Version 1.2
- Changed name from
XPTaskBar
to XPExplorerBar
.
- Added show/hide animation.
- Improved theme support.
- 3 June 2004 - Version 1.1
- Added collapse/expand multiple
Expando
s.
- Added custom XP theme support.
- 31 May 2004 - Initial release.