Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

WPFSpark v1.2

5.00/5 (21 votes)
15 Mar 2016MIT11 min read 89.3K   1.4K  
The next version of the useful WPF controls is here

Image 1

WPFSpark v1.2

At last, it's here! After a really long gap of nearly 4 years, I am happy to announce that the next version of WPFSpark is finally released. :)

What's new in WPFSpark v1.2

In this section I will be providing a summary of new features and modifications made to the WPFSpark controls so that you can adapt your code quickly and integrate new features with ease. For WPFSpark v1.1, I had written several articles, explaining in detail, how each of the controls was designed and implemented. You can see those articles here (WPFSpark: M of N series). I intend to update these articles as soon as possible. For the time being, this article should bring you up to speed. All the code has been ported to .NET framework 4.6.1 using C# 6.0.

SprocketControl

Image 2

None of the existing dependencies have been changed. However, in order to give the user more freedom, two new dependency properties have been added - InnerRadius and OuterRadius. They govern the length of the spoke. They are represented as a ratio of the radius of the inner circle and outer circle (between which the spokes lie) with the width of the SprocketControl, respectively.

Image 3

Dependency Property Type Description Default Value
InnerRadius Double Gets or sets the ratio of the Inner Radius to the Width of the SprocketControl. 0.175
OuterRadius Double Gets or sets the ratio of the Outer Width to the width of the SprocketControl. 0.3125

ToggleSwitch

Image 4

When WPFSpark v1.1 was released, users reported of a memory leak (it can be found here) in the FluidMoveBehavior. ToggleSwitch uses FluidMoveBehavior in order to animate its content when its IsChecked state changes. I looked into various possible solutions to solve this issue but none of them proved satisfactory. Then I decided to remove ToggleSwitch's dependency on FluidMoveBehavior completely. The content of ToggleSwitch is hosted inside a Grid and FluidMoveBehavior is used to animate the movement of the content from one column of the Grid to another. So instead of hosting the content inside a Grid, they are now hosted in a Canvas and instead of using the FluidMoveBehavior, DoubleAnimation is used to animate the Margin of the content.

While implementing this change, it made me look deeper into the ToggleSwitch code and also the issues and suggestions reported by users in the CodePlex site. It thus triggered several other changes (and ultimately a huge rewrite) in order to make ToggleSwitch easier to use while eliminating potential issues (both visual and in code). Here are the changes:

By default, the IsThreeState property is set to False as ToggleSwitch supports only two states for the IsChecked property - True and False. Setting the IsChecked property will not have any visual effect on ToggleSwitch.

The following Dependency Properties have been removed

  • TargetColumnInternal
  • ThumbGlowColor - replaced by ThumbGlowBrush
  • ThumbShineCornerRadius
  • ThumbWidth - replaced by ThumbWidthRatio. ThumbWidth is now a read-only property which represents the actual width of the Thumb.

The following read-only Dependency Properties have been added

Dependency Property Type Description
CheckedMargin Thickness Gets the calculated Margin of the PART_ContentGrid when the ToggleSwitch is in Checked state.
UncheckedMargin Thickness Gets the calculated Margin of the PART_ContentGrid when the ToggleSwitch is in Unchecked state.
ThumbWidth double Gets the calculated width of the Thumb.
ThumbHeight double Gets the calculated height of the Thumb.
ThumbCornerRadius CornerRadius Gets the calculated CornerRadius of the Thumb.

The following new Dependency Properties have been added

Dependency Property Type Description Default Value
CheckedTextEffect Effect Gets or sets the effect to be applied on the Checked Text. null
UncheckedTextEffect Effect Gets or sets the effect to be applied on the Unchecked Text. null
ThumbGlowBrush Brush Gets or sets the Brush for the Glow in the Thumb which is shown when the mouse hovers over the ToggleSwitch. Transparent
ThumbShineBrush Brush Gets or sets the Brush for the shine on the Thumb. Transparent
ThumbWidthRatio Double Gets or sets the ratio of the Width of the Thumb to the Width of the ToggleSwitch. Value Range: 0.1 - 0.9, inclusive. 0.4
OptimizeRendering Boolean Gets or sets the property which indicates whether the ClipBorder surrounding the ToggleSwitch should enable OptimizeClipRendering to prevent gaps between the border and the clipped content. Set this value to False, if the ToggleSwitch Background is Transparent or has partial transparency. Otherwise, if the Background is opaque, set this value to True for better rendering.. False
OptimizeThumbRendering Boolean Gets or sets the property which indicates whether the ClipBorder surrounding the ToggleSwitch Thumb should enable OptimizeClipRendering to prevent gaps between the border and the clipped content. Set this value to False, if the ToggleSwitch ThumbBackground is Transparent or has partial transparency. Otherwise, if the ThumbBackground is opaque, set this value to True for better rendering.. False
AutoThumbWidthRatio Boolean Gets or sets the property which indicates whether the ThumbWidthRatio should be automatically calculated based on the Width, Height and BorderThickness of the ToggleSwitch. This property has higher precedence over the ThumbWidthRatio property. If this property is set to true, any value for ThumbWidthRatio, set by the user, will be ignored and ThumbWidth will be equal to ThumbHeight. True

Golden Rules for ToggleSwitch

Although, ToggleSwitch gives you the freedom to set the values of its Dependency Properties from a vast range of values, in order to have the ToggleSwitch render effectively, just follow these golden rules:

  • Provide uniform values for BorderThickness and ThumbBorderThickness
  • BorderThickness and ThumbBorderThickness should be proportionate i.e. if BorderThickness is {a,b,a,b}and ThumbBorderThickness is {c,d,c,d} then (a/b) should be equal to (c/d).
  • Provide uniform values for CornerRadius. If you are providing non-uniform values, try to ensure that the radii are horizontally (e.g. {a,a,b,b} ) or vertically (e.g. {a,b,b,a}) symmetrical.
  • Ensure that the CornerRadius is less than or equal to half of the ToggleSwitch's height.
  • If you have Background and ThumbBackground as non-transparent colors, then set the OptimizeRendering and OptimizeThumbRendering properties to true.
  • Set the AutoThumbWidthRatio to true and let the ToggleSwitch calculate the best ThumbWidth.

In the source code, in the file ToggleSwitch.Generic.xaml, along with the ControlTemplate for ToggleSwitch I have also added several styles which use the template. These style mimic the user experience of Toggle buttons found in Windows 10 and iOS. You must add the ToggleSwitch.Generic.xaml in your App.xaml to gain access to these styles. The list of styles are:

  • ToggleSwitch.UWP.Light.Style - Represents the Windows 10 ToggleButton for light backgrounds.

    Image 5

  • ToggleSwitch.UWP.Dark.Style - Represents the Windows 10 ToggleButton for dark backgrounds.

    Image 6

  • ToggleSwitch.iOS.Light.XXXX.Style - Represents the iOS ToggleButton for light backgrounds where XXXX refers to the accent color.

    Image 7

You can derive from these styles to create your own styles with the accent color of your choice. You can refer to these styles in your XAML in the following way:

XML
<wpfspark:ToggleSwitch Grid.Row="1"
						  Grid.Column="1"
						  HorizontalAlignment="Center"
						  VerticalAlignment="Center"
						  Style="{StaticResource {ComponentResourceKey TypeInTargetAssembly=wpfspark:ToggleSwitch, ResourceId=ToggleSwitch.UWP.Dark.Style}}" />

ClipBorder

ClipBorder class deserves an honorable mention here. ToggleSwitch would not exist if it were not for the ClipBorder class. In WPFSpark v1.1, ClipBorder class derived from Border class and set the Clip property to clip its child within its bounds. However, that did not prove too effective. In certain scenarios, the ClipBorder did not render correctly. For example, when the ClipBorder had a thick border and both the BorderBrush and Background were the same color, you could see a small gap between the border and the background, especially at the round corners. Initially I thought it was due to the Clip Geometry that was being calculated for the ClipBorder's child based on its borders. I tried different solutions (like adding a small tolerance value while calculating the Clip Geometry) but it did not eliminate the issue effectively.

Then I found out that the problem was not with ClipBorder. The Border class also displayed the same behavior.

Image 8

This made me dig deep into the Microsoft Reference Source for the Border class and come up with an optimized solution of my own. ClipBorder no longer derives from Border class. It now derives from the Decorator class and clips its child more effectively than previously.

FluidWrapPanel

Image 9

In WPFSpark v1.1, FluidWrapPanel imposed a restriction that all its Children must have the same size (defined by ItemWidth and ItemHeight). One of the top feature requests made by users was to remove this restriction and allow adding Children having different dimensions. Initially, I thought it was difficult to achieve and it would require some crazy code modifications. Then I came up on the idea of using BitMatrix to track the positions of the Children and calculate the placement of a child while it was being dragged. This led to the implementation of the FluidBitMatrix class which replaced the FluidLayoutManager class.

However, there is one restriction - the Children must have dimensions which are multiples of ItemWidth and ItemHeight. I have also added a read-only Dependency Property FluidItems which is an ObservableCollection of the Children. By accessing this property you can obtain the current order of the Children in the FluidWrapPanel and also be notified of changes when a child is dragged to a new location. Another Dependency Property which I have added is the OptimizeChildPlacement which governs the algorithm to calculate the best available position for placing a child in the FluidWrapPanel.

Dependency Property Type Description Default Value
OptimizeChildPlacement Boolean Gets or sets the property that indicates whether the placement of the children is optimized. If set to true, the child is placed at the first available position from the beginning of the FluidWrapPanel. If set to false, each child occupies the same (or greater) row and/or column than the previous child. true

SparkWindow

Image 10

SparkWindow now has the same look and feel as a Desktop Window in Windows 10. The About button has been removed. I was able to add the blur behind option (blurred glass effect) to the Window based on the excellent tip from the blog article by Rafael Rivera - Adding the "Aero Glass" blur to your Windows 10 apps.​

NVM#, an app which I recently released, uses SparkWindow. So does the WPFSparkClient which shows the examples of the controls in WPFSpark. Both of these apps show how a SplitViewMenu can be used in a WPF application. (SplitView Control does not exist in WPF!)

Important Note: Whenever you instantiate a SparkWindow programatically, ensure that you set the properties AllowTransparency=true and WindowStyle=None before calling the ShowDialog() method. Otherwise it would throw an exception.

Three new Dependency Properties have also been added - TitleImage, TitleImageMargin, TitleMargin.

Dependency Property Type Description Default Value
TitleImage UIElement Gets or sets the UIElement (usually an Image) to be displayed in the TitleBar of the Window. null
TitleImageMargin Thickness Gets or sets the Margin of the TitleImage. 0
TitleMargin Thickness Gets or sets the Margin of the Title text in the Title Bar. 0

Update

SparkWindow now supports resizing. Make sure you set the ResizeMode property to CanResize. This is set in the default SparkWindow template. This allows the SparkWindow to be resized by dragging the edges or the corners.

FluidPivotPanel

Image 11

PivotHeaderControl

In order to prevent a Pivot Header from being selected by the user, you can set the IsEnabled property to False. Also a new Dependency Property DisabledForeground has been added to define the foreground of the PivotHeader when it is in disabled state.

Dependency Property Type Description Default Value
DisabledForeground Brush Gets or sets the Foreground of the PivotHeaderControl when it is in disabled state Black

PivotPanel

A new API SelectHeaderByName has been added which allows you to select a PivotHeaderControl via code. It takes the name of the PivotHeaderControl as argument.

FluidProgressBar

Image 12

No changes have been made. The control should work in the same way as it did in WPFSpark v1.1.

FluidStatusBar

Image 13

I have added a Dependency Property SyncLatest. When it is set to True, only the latest message will be displayed. The older messages which have not been displayed yet will be discarded. When the property is set to False, the messages will be enqueued and shown one after the other.

Dependency Property Type Description Default Value
SyncLatest Boolean Gets or sets the property which indicates whether the display of status message is synced with the latest message. If set to true, when messages arrive, they are not enqueued to be displayed. Instead the latest one is displayed and the older ones are discarded. False

Using WPFSpark v1.2 in your code

WPFSpark v1.2.0.1 is available in NuGet. You can obtain it here. Alternatively, you can add it to your project from Visual Studio using the Manage NuGet Packages option (Just right click on your project in the Solution Explorer and click on Manage NuGet Packages).

If you are interested in getting your hands dirty with code, you can access the WPFSpark source code in GitHub. I have moved the code from CodePlex to GitHub as I feel it is easier to manage your code in GitHub. Also the code is available under MIT License.

History

  • 26-February-2016: Added Resize feature to SparkWindow
  • 08-December-2015: WPFSpark v1.2.0.2 released
  • 01-December-2015: WPFSpark v1.2.0.1 released

License

This article, along with any associated source code and files, is licensed under The MIT License