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.
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

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 nuget.exe and 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
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.cmd
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! :)

WPFSpark v1.2: Status

It has been almost two weeks since I started my work on WPFSpark v1.2 and here is the status so far:

SprocketControl, ToggleSwitch, SparkWindow, FluidProgressBar & FluidStatusBar have been successfully upgraded to .NET 4.6. Yay! Only FluidPivotPanel and FluidWrapPanel remain to be upgraded. ToggleSwitch has been rewritten from scratch and has more robust features now. It demanded my biggest attention and it caused the ClipBorder class being rewritten from the scratch too. Compared to these classes, the other controls have been incorporated with fewer changes.

Once I complete the .NET 4.6 version, porting it to .NET 4.5.2 should not take much time. What might take more time instead is combining these two into a single solution using the Shared Project template. I am still doubtful about it. If it takes longer to achieve it, I might postpone it and release the two versions separately now (one for 4.6 and the other for 4.5.2).

UWP version of WPFSpark might get delayed! Let’s keep our fingers crossed!

Back to code!

Back again

Hi everyone!

My last post was in January 2013. It been a long time since then and a lot has happened in my life too in the past few years – changing jobs to changing location! I couldn’t devote much time to my pet projects & my blog. But now I am back once again with some good news.

I have once again starting giving time to my projects and the first fruit of this labor is the NVM# project which is a complete rewrite of my NVM project (my first project when I began my adventure with .NET) for the Windows 10 OS. It has the same look and feel of the Settings app and provides an effective way of managing and sharing your Environment variables.

nvmsharp

You can read more about it in my CodeProject article here.

Many folks have been asking me when I am planning to release WPFSpark v1.2. First of all, I would like to apologize for the delay in releasing v1.2. Second, it gives me immense pleasure to know that people are really liking my WPFSpark library and are eagerly waiting for the next version. Well the good news is I have begun working on v1.2 and am hoping to release it by the end of this month (November, 2015). Here is my plan of action for v1.2

  1. Bug fixes that have been reported in Codeplex site.
  2. Prioritizing of new features requested by users.
  3. Moving codebase to GitHub. Yes I will be moving the code to GitHub because I find it easier to use and collaborate there. Moreover, Visual Studio 2015 provides great integration with GitHub. It is the main reason I released NVM# in GitHub.
  4. UWP version of WPFSpark. Yes there will be a UWP version of WPFSpark! However not all controls will be ported at one go. Instead they will be added incrementally. I am still contemplating whether to port some of the controls like ToggleSwitch and FluidPivotPanel as there are similar controls available in UWP. The good news is that I had already ported FluidWrapPanel to WinRT for my FloTiles app and it will be the first one to be ported to UWP.
  5. I am still investigating on how to create a single code base for WPFSpark in GitHub which can cater to multiple dot Net frameworks and UWP. The Shared Project Template in Visual Studio might come handy. I am still investigating on that!
  6. Speaking of multiple dotNet frameworks, I am currently planning to release v1.2 for .NET 4.5, 4.6 and UWP. I haven’t decided whether to release for .NET 4.0. (Folks, do let me know! I might add it later)

Well that’s it for now! I will be back with more good news soon!

Time to code!

Visual Studio:TaskKill only if Process exists

My primary tool for development is Visual Studio. Often while building and testing applications, I have face the following scenario numerous times:

  • I build and run the application (Ctrl + F5).
  • I test my application and feel the need for some more changes in the code.
  • I go back to the code and modify and build again.
  • Visual Studio gives me the following error message:

Unable to copy file “MyApp.exe” to “\Debug\MyApp.exe”. The process cannot access the file ‘..\Debug\MyApp.exe’ because it is being used by another process.
Only then I realize that I had forgotten to close the application before rebuilding. :(

I was thinking of finding a way to automatically close the application before each build. Initially I put the command “taskkill /f /im MyApp.exe” in the Pre-Build events of the project but this worked only if the application was running. If the application was already closed, the build failed with an error message saying that the script failed with an exit code 1.

I then found another solution on the web (link). This still gave me the same error. So, I tweaked it further to arrive at this script:

tasklist /FI "IMAGENAME eq $(TargetName).exe" 2>NUL | find /I /N "$(TargetName).exe">NUL
if "%ERRORLEVEL%"=="0" (taskkill /f /im $(TargetName).exe
) else ( exit 0)

It proved very effective and time-saving too!

Note: The above script will work only if you are building an .exe application. If you are building a DLL, try putting the name of the application, which is using the DLL, in place of $(TargetName).

Happy Coding! :)

P.S. I found another simpler solution here

taskkill /F /IM $(TargetName).exe 2>&1 | exit /B 0

FluidMoveBehavior Bug (& Memory Leak!)

Back in August, two people, tmccowan and Bullimann, brought into my notice a bug associated with the FluidMoveBehavior in WPF. This issue can be found here. Since one of the controls (ToggleSwitch) in my WPFSpark project was using this behavior, the issue was preventing the garbage collection of the control. According to the post, the static TagDictionary in FluidMoveBehaviorBase is holding references of the associated objects and thus preventing them from being GCed.

Steve Greatrex posted a workaround subscribe to the UserControl.Unloaded event and in the handler call the Detach method of the FluidMoveBehavior.
I tried this workaround and did a memory profiling with ANTS Memory Profiler  (a really great tool!). To my dismay, this workaround had little effect. I thought the Detach method would remove the reference of the ToggleSwitch’s internal Grid but it didn’t. So the instances of ToggleSwitch kept piling in memory each time they were instantiated. (see images)

MemProfile1

MemProfile2
I debugged the code and dug in deeper into the FluidMoveBehaviorBase to see the contents of the TagDictionary object. In this dictionary, the Key is the object to which FluidMoveBehavior is added and the Value is an internal class called TagData which encapsulates the following properties: The object itself(Child), the object’s Parent, ParentRect, AppRect, TimeStamp and InitialTag.
So I thought of a different workaround using Reflection. In the UserControl.Unloaded event handler:
1. Get access to the TagDictionary field in the FluidMoveBehaviorBase.
2. Invoke the ContainsKey method to check if the object is added as a key in the dictionary.
3. If ContainsKey method returns true, then invoke the Remove method to remove the object from the dictionary.

private void OnUnloaded(object sender, RoutedEventArgs e)
{
    this.Unloaded -= OnUnloaded;
    DetachFluidMoveBehavior(rootGrid);
}

private void DetachFluidMoveBehavior(DependencyObject depObj)
{
    if (depObj != null)
    {
        foreach (var b in Interaction.GetBehaviors(depObj).OfType<FluidMoveBehavior>())
        {
            b.IsActive = false;
            b.Detach();
            // HACK: This hack is to remove the depObj from the TagDictionary collection using reflection as 
            // the TagDictionary collection is holding up the reference of depObj leading to its non-garbage collection of depObj (a.k.a Leak!)
            FieldInfo fieldInfo = typeof(FluidMoveBehaviorBase).GetField("TagDictionary", BindingFlags.Static | BindingFlags.NonPublic);
            if (fieldInfo == null)
                continue;

            // Get the TagDictionary object
            var tagDict = fieldInfo.GetValue(b);

            // Get the ContainsKey MethodInfo
            MethodInfo miContainsKey = fieldInfo.FieldType.GetMethod("ContainsKey");
            if (miContainsKey != null)
            {
                // Does the TagDictionary contain depObj as a key?
                bool containsKey = (bool)miContainsKey.Invoke(tagDict, new object[] { depObj });
                if (containsKey)
                {
                    // Get the Remove Method Info
                    MethodInfo miRemove = fieldInfo.FieldType.GetMethod("Remove");
                    if (miRemove != null)
                    {
                        // Remove the depObj from the TagDictionary
                        miRemove.Invoke(tagDict, new object[] { depObj });
                    }
                }
            }
        }
    }
}

Though this is a crude solution, it does its job.

This workaround has been incorporated in WPFSpark v1.2 which I will be releasing soon.

I hope Microsoft fixes this issue in the next release. :)