CompositionProToolkit v0.3 Released

cpt_banner

Its done!

CompositionProToolkit v0.3 has been released on GitHub and NuGet.

I have successfully ported the FluidWrapPanel code in WPFSpark v1.3 to UWP and replaced the XAML animations used in FluidWrapPanel with Composition animations. This has resulted in smoother animations in FluidWrapPanel control.

Here is the FluidWrapPanel in action

FWP

WPFSpark v1.3 Released

Yesterday (Jul 10th, 2016), I released WPFSpark v1.3 on GitHub & NuGet. In this version I have updated the Layout logic of FluidWrapPanel with a more robust code. Now it rearranges the variable sized children in a more efficient manner.

Also, I upgraded the target DotNet Framework of the WPFSpark project from 4.6.1 to 4.6.2.

If you are installing this version in your project, please ensure that your project is also targeting the version 4.6.2 of the DotNet Framework.

Retiring WPFSpark.UWP project

I will be retiring the WPFSpark.UWP project soon. Having controls used for UWP project and keeping the project name “WPFSpark” did not make sense (as WPF is limited to Windows 10 desktop projects). As of now WPFSpark.UWP project contains only the FluidWrapPanel control. I will be moving the control (and its source code) to the CompositionProToolkit project.

CompositionProToolkit

CompositionProToolkit is a collection of helper classes for Windows.UI.Composition. It also contains the FluidProgressRing control which is a concept design for a modern version of the ProgressRing control in UWP.

FluidProgressRing.gif

I have currently ported the FluidWrapPanel code in WPFSpark v1.3 to UWP and now I am trying to use Windows.UI.Composition APIs to replace the XAML animations used in FluidWrapPanel. This would result in smoother animations in FluidWrapPanel control. This work is currently in progress and I hope to release it soon.

CompositionExpressionToolkit

In this post, I will be introducing you to another project of mine which I started this month in GitHub – CompositionExpressionToolkit.

cet_banner

Since Build 2016, I have started looking into Windows.UI.Composition APIs. These APIs are present in a layer between the XAML layer and the DirectX layer. They provide more powerful features than the XAML layer and also have a less steep learning curve than the DirectX layer. Composition APIs help to make your UI faster and more fluid. They definitely add a wow factor to your UI which might have not been possible with coding entirely in XAML.

If you are still unconvinced about Composition APIs, read the Why even use Composition Section in this blog. (TL;DR Composition APIs work outside your application process and will continue to render animations at 60 FPS even if your UI thread is blocked!)

So you might be wondering where CompositionExpressionToolkit fits in. Well, according to MSDN, ExpressionAnimation and KeyFrameAnimation use a mathematical expression to specify how the animated value should be calculated each frame. The expressions can reference properties from composition objects. Currently, the mathematical expression is provided in the form of a string. Expression animations work by parsing the mathematical expression string and internally converting it to a list of operations to produce an output value.

Well, using a string for creating an expression increases the chance of introducing errors (spelling, type-mismatch to name a few). These errors will not be picked up during compile time and can be difficult to debug during runtime too.

To mitigate this issue, we can use lambda expressions which are statically typed and allow the common errors to be caught during compile time. But how do you convert them to the appropriate string format to pass it as an input to the ExpressionAnimation / KeyFrameAnimation? This is where CompositionExpressionToolkit fits in. It provides several extension methods which take in a lambda expression as input and convert it to an appropriate string format which will be accepted by the ExpressionAnimation / KeyFrameAnimation.

CompositionExpressionToolkit also provides several other extension methods and helper classes which make it easier to work with Windows.UI.Composition.

Check out the CompositionExpressionToolkit GitHub page to know more details.

If you want to try out CompositionExpressionToolkit in your own project, it is available in NuGet too. To install CompositionExpressionToolkit, run the following command in the Package Manager Console in Visual Studio

Install-Package CompositionExpressionToolkit

Note: The current version of CompositionExpressionToolkit (v0.1.7.1) requires Windows SDK Preview 14332.

If you want to learn more about Windows.UI.Composition concepts then the following links will give you a good start –

Dynamic FluidWrapPanel using AdaptiveTriggers

A few days ago, I was asked if the FluidWrapPanel could resize its children uniformly to use the maximum available space. My initial response was that FluidWrapPanel acts as a container and does not influence its children’s sizes. If it resized its children’s size to a very small size then it may make the content unreadable.

Then I got further details of the requested scenario – The FluidWrapPanel has 12 children. When the size of the FluidWrapPanel changes the layout of the children should also change (they should also be resized to occupy the maximum available space). For example when the FluidWrapPanel is displayed in Portrait mode (having a certain width), the children should be displayed in a 6 x 2 layout, when in Landscape mode (having medium size) they should be displayed in 4 x 3 layout and when in Landscape mode (with maximum width) the layout should change to 3 x 4. All this should happen without affecting the fluidity of the FluidWrapPanel.

DynamicFWP

Well, let me explain FluidWrapPanel’s behavior in this scenario. FluidWrapPanel will not know whether the children should be displayed in a 6 x 2 layout, a 4 x 3 layout or in a single row. Its logic for arranging its children is governed by the following factors

  • ItemWidth dependency property
  • ItemHeight dependency property

If the child’s width and height are less than the ItemWidth and ItemHeight respectively, there will be a gap between adjacent children. If they are more, the adjacent children with overlap each other.

So the solution is to listen to the SizeChanged event of the FluidWrapPanel and when it occurs

  • Calculate which layout needs to be displayed in the FluidWrapPanel
  • Based on the layout and the size of the FluidWrapPanel, calculate the desired item width and height.
  • Set each of the child’s width and height to the calculated item width and height respectively.
  • Set the ItemWidth and ItemHeight dependency properties of the FluidWrapPanel to the calculated item width and height respectively.

This solution works best when all the children are of same size i.e. having width and height equal to the ItemWidth and ItemHeight respectively.

Since this solution is applicable mainly in UWP applications, I thought it was best to utilize AdaptiveTriggers to solve this issue with ease.

I made a sample UWP project to implement this solution. Here is what I did.

1. Create a New Universal Project and add reference to WPFSpark.UWP NuGet package.

2. Create a UserControl called FluidItemControl which will be a child to the FluidWrapPanel. It just consists of a border (having random background) and a textblock (showing a number).

I came upon a strange behavior of Page class. If you add a new dependency property to MainPage.xaml.cs and try to bind to it in MainPage.xaml, then that property will not be recognized. After trying out several ways unsuccessfully, I found a workaround in StackOverflow. It seems you have to define a base class, say PageBase, which derives from Page and then define your dependency property there. Then MainPage should derive from PageBase. Now the binding will work. Strange but true!
3. So here is the definition of PageBase class.
public class PageBase : Page
{
    public enum PageDisplayType
    {
        None = 0,
        Display3x4 = 1,
        Display4x3 = 2,
        Display6x2 = 3
    }

    #region PageDisplay
    /// <summary>
    /// PageDisplay Dependency Property
    /// </summary>
    public static readonly DependencyProperty PageDisplayProperty =
        DependencyProperty.Register("PageDisplay", typeof(PageDisplayType), typeof(MainPage),
            new PropertyMetadata(PageBase.PageDisplayType.None, OnPageDisplayChanged));

    /// <summary>
    /// Gets or sets the PageDisplay property. This dependency property 
    /// indicates the number of rows and columns to set in the FluidWrapPanel.
    /// </summary>
    public PageBase.PageDisplayType PageDisplay
    {
        get { return (PageBase.PageDisplayType)GetValue(PageDisplayProperty); }
        set { SetValue(PageDisplayProperty, value); }
    }

    /// <summary>
    /// Handles changes to the PageDisplay property.
    /// </summary>
    /// <param name="d">MainPage</param>
    /// <param name="e">DependencyProperty changed event arguments</param>
    private static void OnPageDisplayChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var page = (PageBase)d;
        var oldPageDisplay = (PageBase.PageDisplayType)e.OldValue;
        var newPageDisplay = page.PageDisplay;
        page.OnPageDisplayChanged(oldPageDisplay, newPageDisplay);
    }

    /// <summary>
    /// Provides derived classes an opportunity to handle changes to the PageDisplay property.
    /// </summary>
    /// <param name="oldPageDisplay">Old Value</param>
    /// <param name="newPageDisplay">New Value</param>
    async void OnPageDisplayChanged(PageBase.PageDisplayType oldPageDisplay, PageBase.PageDisplayType newPageDisplay)
    {
        switch (newPageDisplay)
        {
            case PageBase.PageDisplayType.Display3x4:
                rows = 3;
                columns = 4;
                break;
            case PageBase.PageDisplayType.Display4x3:
                rows = 4;
                columns = 3;
                break;
            case PageBase.PageDisplayType.Display6x2:
                rows = 6;
                columns = 2;
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(newPageDisplay), newPageDisplay, null);
        }

        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, RefreshPanel);
    }

    #endregion

    protected double rows = 0;
    protected double columns = 0;

    protected virtual void RefreshPanel()
    {
        
    }
}

4. I defined the AdaptiveTriggers in MainPage.xaml. These triggers will change the PageDisplay dependency property based on the width of the MainPage.

<local:PageBase x:Class="TestFWPanel.MainPage"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="using:TestFWPanel"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:wpfSpark="using:WPFSpark"
                x:Name="RootPage"
                mc:Ignorable="d">
    <local:PageBase.Resources>
        <x:Double x:Key="SmallScreenWidth">0</x:Double>
        <x:Double x:Key="MediumScreenWidth">540</x:Double>
        <x:Double x:Key="LargeScreenWidth">900</x:Double>
    </local:PageBase.Resources>
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState x:Name="Small">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="{StaticResource SmallScreenWidth}" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="RootPage.PageDisplay"
                                Value="Display6x2"></Setter>
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Medium">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="{StaticResource MediumScreenWidth}" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="RootPage.PageDisplay"
                                Value="Display4x3" />
                    </VisualState.Setters>
                </VisualState>
                <VisualState x:Name="Large">
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="{StaticResource LargeScreenWidth}" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="RootPage.PageDisplay"
                                Value="Display3x4" />
                    </VisualState.Setters>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Grid x:Name="ContainerGrid"
              HorizontalAlignment="Stretch"
              VerticalAlignment="Stretch">
            <wpfSpark:FluidWrapPanel x:Name="fwPanel"
                                     Background="Beige"
                                     Margin="0"
                                     HorizontalAlignment="Stretch"
                                     VerticalAlignment="Stretch"
                                     ItemWidth="2"
                                     ItemHeight="2"
                                     IsComposing="True"
                                     SizeChanged="OnFWPSizeChanged"></wpfSpark:FluidWrapPanel>
        </Grid>
    </Grid>
</local:PageBase>

5. The size of the FluidWrapPanel also changes when the size of the MainPage changes. I am calling the RefreshPanel() method when this happens. This method updates the ItemWidth and ItemHeight properties along with the sizes of the children accordingly.

protected override void RefreshPanel()
{
    if ((rows.IsZero()) || (columns.IsZero()))
        return;

    var width = Math.Floor(fwPanel.Width/columns);
    var height = Math.Floor(fwPanel.Height/rows);

    foreach (var child in fwPanel.FluidItems.OfType<FluidItemControl>())
    {
        child.Width = width;
        child.Height = height;
    }

    fwPanel.ItemWidth = width;
    fwPanel.ItemHeight = height;
}

You can find the full source code here.

WPFSpark v1.2.1.1 Released

wpfspark_title_512x128

Hello everyone. An update to WPFSpark has been released. WPFSpark v1.2.1.1 brings an update which allows ToggleSwitch control to show the current Windows Accent Color. It even dynamically updates its color when the user changes the  Accent Color.

For this purpose, I have split the ToggleSwitch Control Template into two – Basic and Modern. The ToggleSwitchBasicTemplate is to be used when you are displaying text within the ToggleSwitch control for the Checked and Unchecked state.

ToggleSwitch_Basic

There is a predefined style using the ToggleSwitchBasicTemplate which can be used like this

<wpfspark:ToggleSwitch 
	Style="{StaticResource {ComponentResourceKey TypeInTargetAssembly=wpfspark:ToggleSwitch, ResourceId=ToggleSwitch.Basic.Style}}" />

ToggleSwitchModernTemplate is to be used to emulate the look and feel of the toggle switch in Windows 10 Mobile and iOS.

There are three predefined styles using the ToggleSwitchModernTemplate –

  • ToggleSwitch.UWP.Light.Style – UWP Style ToggleSwitch for light background.
ToggleSwitch_w10_Light
<wpfspark:ToggleSwitch 
	Style="{StaticResource {ComponentResourceKey TypeInTargetAssembly=wpfspark:ToggleSwitch, ResourceId=ToggleSwitch.UWP.Light.Style}}" />
  • ToggleSwitch.UWP.Dark.Style – UWP Style ToggleSwitch for light background.
ToggleSwitch_w10_Dark
<wpfspark:ToggleSwitch 
	Style="{StaticResource {ComponentResourceKey TypeInTargetAssembly=wpfspark:ToggleSwitch, ResourceId=ToggleSwitch.UWP.Dark.Style}}" />
  • ToggleSwitch.iOS.Light.Style – iOS Style ToggleSwitch for light background.
ToggleSwitch_iOS
<wpfspark:ToggleSwitch 
	Style="{StaticResource {ComponentResourceKey TypeInTargetAssembly=wpfspark:ToggleSwitch, ResourceId=ToggleSwitch.iOS.Light.Style}}" />

WPFSpark.UWP : Creating a single NuGet package containing x86, x64 and ARM binaries

wpfspark_title_uwp_512x128

Hello again! I have another good news to share with you. WPFSpark.UWP v1.2 is released today.:) . You can get the NuGet package from here. You can view the source code here. In this blog I will explain in detail how I created the NuGet package for WPFSpark.UWP.
Update(Jul 14, 2016): I have updated this article to mention that the nuget.exe file should be placed in the root folder of the project (not in the NuGet folder). If you place the nuget.exe file in the NuGet folder then it will also be packaged within your Nuget package, thus increasing your Nuget package size drastically (~1.5 MB).
If you have already created your directory structure, you just have to move the nuget.exe file from the NuGet folder to the root folder of the project and modify the CreateNugetPackage.cmd file accordingly.
For the past few weeks I have been trying to port the WPFSpark library to the Universal Windows Platform (UWP). Since most of the controls in WPFSpark are already present natively (like ToggleSwitch, Inderminate ProgressBar, ProgressRing to name a few), porting some of the controls would create redundant controls in UWP. So the only control eligible for porting to UWP from WPF was the FluidWrapPanel.
I was able to port the control with minimal changes. The FluidMouseDragBehavior has been renamed to FluidPointerDragBehavior. A reference to the Microsoft.Xaml.Behaviors.Uwp.Managed NuGet package was added for the Behavior class from which FluidPointerDragBehavior is derived.
Ok, now the control has been successfully ported and it’s time to create the NuGet package. However, I wanted to create a NuGet package which contained all the three binaries – x86, x64 & ARM. I did not want to create separate binaries for each and upload them to NuGet. I wanted to have a single NuGet package which, when referenced by a project, would add reference to the appropriate binary based on the platform for which the project is being built.
The search for an apt solution led me here. I tested it out by creating a sample project, SampleBehaviorLib. Basically, I was using the build and lib folders to create a NuGet package. (If you want to know more about the directory structure that has to be used to create NuGet packages, see here). The build folder contained 3 folders: x86, x64 & ARM each of which contained the respective binary. The lib folder contained the x86 version. The lib folder will allow the Visual Studio to work properly in Designer mode. The build folder also contained a .targets file which added the logic for selecting the appropriate binary based on the build platform.
Unfortunately, the above solution did not work for me. When I referenced the NuGet package (created using the above method) in another project, it built successfully for x86 platform. But for x64 and ARM version, the build failed. It gave the following error
1>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\AppxPackage\Microsoft.AppXPackage.Targets(1151,5): error APPX1101:Payload contains two or more files with the same destination path 'SampleBehaviorLib.dll'. Source files: 
 1>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\AppxPackage\Microsoft.AppXPackage.Targets(1151,5): error APPX1101: C:\Users\Guest01.nuget\packages\SampleBehaviorLib\1.0.8\lib\uap10.0\SampleBehaviorLib.dll
 1>C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\AppxPackage\Microsoft.AppXPackage.Targets(1151,5): error APPX1101: C:\Users\Guest01.nuget\packages\SampleBehaviorLib\1.0.8\build\uap10.0\x64\SampleBehaviorLib.dll
I visited the NuGet project in GitHub and raised this issue. The nice folks there helped me out. It seems I had to use the ref and runtimes folder instead of the lib and build folder. I revisited the NuGet 3 Package Authoring Document and I found out the following:
Ref folder: ref is a new, optional, directory that contains .NET assemblies defining the public surface (public types and methods) for an application to compile against. The assemblies in this folder may have no implementation, they are purely used to define surface area for the compiler. If the package has no ref directory, then the lib is both the reference assembly and the implementation assembly. It is useful for packages that need to provide a consistent surface area for compilation and intellisense but then have different implementation for different TxMs. [A TxM is the name of a platform that a given asset in a package is supposed to work for. Logically these are an extension of the Target Framework Monikers (TFM) e.g. net45, net46, netcore50, and dnxcore50 are all examples of TxMs. For UWP applications for Windows 10, the TxM  is uap10.0.]
Runtimes folder: runtimes is a new, optional, directory that will contain OS specific code, such as CPU architecture and OS specific or otherwise platform-dependent binaries. The runtimes folder contains assemblies and native libraries required to run on specific “runtimes”, which are generally defined by Operating System and CPU architecture. These runtimes are identified using Runtime Identifiers (RIDs) such as win, win-x86, win7-x86, win8-64, etc. For Windows 10 the RIDs are win10-x86, win10-x64 & win10-arm.
So, I have to compile the WPFSpark.UWP project for the three platforms – x86, x64 & ARM and put them in the appropriate folders within the runtimes folder. Next, I have to create an assembly (for WPFSpark.UWP project)which defines the surface area for the compiler and intellisense i.e. an assembly containing only the declarations of the methods and properties defined by the classes within WPFSpark.UWP project (but no implementation). Hmmm, seems like a tedious task. Fortunately, there is a NuGet package which does the job for you – Microsoft.DotNet.BuildTools.GenAPI. This is currently in beta. Therefore when you add the NuGet package (through Manage NuGet Packages option) make sure you check the Include prerelease option so that it is listed in the search results.
Add_Nuget_GenAPI
This is a very useful package but it does only half the job. According to the documentation of this package
This package provides build-time support generating reference assembly source. Referencing this package will cause the build to produce a CS file in the output directory that represents the public surface area of the project. This package requires .NET Framework 4.6 or later.
I raised an issue in this package’s GitHub forum to know if there was an easy way to automate the creation of an assembly through a script. It seems there isn’t. I got help from the folks at the NuGet project. They said:
“You can create a project with similar characteristics as your implementation dll and include the source. We didn’t try to create a dll since everyone has a different build system with respect to versioning, signing, etc so we just emit a CS that you can plug into your own project.”
Ok, so now I create a Universal Class Library project in Visual Studio, name it WPFSpark.UWP.Ref and add the generated CS file to it. I build it in Release Mode for the AnyCPU platform. The resulting DLL file will be placed in the reference folder.
So now the WPFSpark.UWP project folder structure looks like this

directory_structure_updated

The WPFSpark.UWP folder contains the source code for the controls. The WPFSpark.Ref folder contains the reference project created for the generated CS file and the WPFSparkUWP.Client folder contains a demo app which references the WPFSpark.UWP NuGet package. The NuGet folder contains the ref and runtimes folder along with WPFSpark.UWP.nuspec file. The contents of NuGet folder are used to create the WPFSpark.UWP NuGet package.
The NuGet folder structure looks like this
nuget_directory_structure_updated.png
In order to keep the contents of the runtimes folder up-to-date, I have added the following script in the Build Action of the WPFSpark.UWP project
@echo Copying '$(TargetFileName)' to $(ProjectDir)..\Nuget\runtimes\win10-$(PlatformName)\lib\uap10.0
copy /Y $(TargetPath) $(ProjectDir)..\Nuget\runtimes\win10-$(PlatformName)\lib\uap10.0
This will ensure that whenever a build is made for a particular platform (x86/x64/ARM) the output DLL will be copied to the appropriate location in the runtimes folder.
A similar script has been added to the Build Action of the WPFSpark.UWP.Ref project in order to copy the output DLL to the reference folder.
@echo Copying '$(TargetFileName)' to $(ProjectDir)..\Nuget\ref\uap10.0
copy /Y $(TargetPath) $(ProjectDir)..\Nuget\ref\uap10.0
The CreateNuGetPackage.cmd contains the script for creating the WPFSpark.UWP NuGet package.
 CreateNuGetPackage.png
Hope this helps you create your own NuGet packages containing x86, x84 and ARM binaries.
Happy Coding!:)

WPFSpark 1.2 Released

Happy New Year everyone!

Well last month has been really hectic and crazy (and filled with vacations). Though I released WPFSpark v1.2 on 1st Dec 2015, I couldn’t update my blog. I was busy with the UWP version of WPFSpark and hit a few roadblocks in the Nuget package creation for the same.

wpfspark_title

Check out my CodeProject article which describes the new features and updates that have been incorporated into the controls. You can obtain the Nuget Package from here. The source code repository is now shifted to GitHub. You can access it here.

Now for the UWP version. I have successfully ported FluidWrapPanel to the UWP version. I am trying to create a Nuget Package which contains the x86, x64 and ARM versions in a single package and based on the build configuration of the project using this library, the appropriate version will be selected. I am facing some issues (some folks are helping me out). Should be able to upload the UWP version by this week hopefully.

Happy Coding!:)