I was recently thinking how to deploy the scissors feature center and came accross different ideas. My requirements are pretty simple:
- Easy packaging
- Easy versioning
- Easy updating
- Easy install and clean uninstall
- No admin rights
- Easy hosting and uploading
So here are the canidates I found:
- Clickonce
- Squirrel
- Write something my self
- Windows Store using the Desktop Bridge
Clickonce
It's a useful but also very old technology. I worked with it a lot in the past, but it really has it's problems. Updating is slow, you need to serve the files via http, there is no really easy way to distribute the app to another location. So I started looking for alternatives.
Squirrel
Looks very promising! I played arround with it and tried to get things going, but it required a lot of steps. So I was thinking what my audience is and came up with another idea. The windows store! Maybe I'll investigate in this technology later.
Write something my self
God, no thanks. Don't be stupid that problem is solved already by another person. So let's get started!
Desktop-Bride
To get started to use the Desktop-Brigde make sure you got the following bits installed:
- Visual Studio 2017 version 15.5 or higher
The Desktop Bridge was introduced in Windows 10, version 1607, and it can only be used in projects that target Windows 10 Anniversary Update (10.0; Build 14393) or a later release in Visual Studio.
First make sure you got the right tools installed in Visual Studio.
.NET desktop development
Universal Windows Platform development
So let's follow the instructions:
- In Visual Studio, open the solution that contains your desktop application project.
- Add a Windows Application Packaging Project project to your solution.
You won't have to add any code to it. It's just there to generate a package for you. I'll refer to this project as the "packaging project".
- Set the Target Version of this project to any version that you want, but make sure to set the Minimum Version to Windows 10 Anniversary Update.
- In the packaging project, right-click the Applications folder, and then choose Add Reference.
So the first steps are done! Next we have to do some work in the Package.appxmanifest
file.
- Set the Display-Name:
Scissors.FeatureCenter.Win
. Thats what our app is called in Windows.
- Use the
Visual Asset Generator
to generate tiles and icons for the app. Use at least 400x400 pixels to generate, and use an png image with a transparent background
Use at least a 500x500 png file and hit generate. Thats to make the
Windows App Certification Kit
happy later on. But you can tweak all those thousands of images yourself (or pay a designer to do so) .
- Make sure the
capabilities
are set toInternet (Client)
- Set the
Packaging
information to something unique and useful.
Okay lets build now, you should see something like this in the bin\AnyCPU\Debug
folder
Let's set the package project as startup project and hit F5
:
That sucks :( Basically the error message is saying that it can't write to this particular folder.
So lets look at the limitations of the packaging process:
- In order to contain app state, the bridge attempts to capture changes the app makes to AppData. All write to the user's AppData folder (e.g., C:\Users\user_name\AppData), including create, delete, and update, are copied on write to a private per-user, per-app location.
- Writes to files/folders in the app package are not allowed. Writes to files and folders that are not part of the package are ignored by the bridge and are allowed as long as the user has permission.
Okay now we have to find out how to overcome this limitation.
First of all, we need to change the paths where XAF put's the user generated stuff. Second we want to be our application snappy & launch instant, so we want to pre generate the ModelAssembly.dll
, Model.Cache.xafml
and ModulesVersionInfo
file.
Cause I want the sample to be runnable as a normal WinForms application as well as a WindowsStore app I'll add another project called Scissors.FeatureCenter.Win10
and cause i don't want to duplicate to much code i add a new shared project called Scissors.FeatureCenter.Win.Shared
Move all the stuff from Scissors.FeatureCenter.Win
to the shared project and make a new reference to the shared one:
Let's run. Okay the icon is missing. So go into the Scissors.FeatureCenter.Win
Properties
panel and change the icon location:
Run again. Fine! Everything looks pretty damn good! But it takes almost 8 seconds to launch.
So let's focus next on the Scissors.FeatureCenter.Win10
project. We need to do the same modification with the manifest as in the normal Win project.
Scissors.FeatureCenter.Win10.csproj
:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{199C4A09-1369-4C80-A334-5A225FA8C780}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Scissors.FeatureCenter.Win10</RootNamespace>
<AssemblyName>Scissors.FeatureCenter.Win10</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>..\Scissors.FeatureCenter.Win.Shared\Scissors.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Windows">
<HintPath>..\..\..\..\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.WinMD</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\demos\FeatureCenter\src\Modules\LabelEditorDemos\BusinessObjects\Scissors.FeatureCenter.Modules.LabelEditorDemos.BusinessObjects.csproj">
<Project>{1f9ce801-c633-4b28-a089-ac5536d1b047}</Project>
<Name>Scissors.FeatureCenter.Modules.LabelEditorDemos.BusinessObjects</Name>
</ProjectReference>
<ProjectReference Include="..\demos\FeatureCenter\src\Modules\LabelEditorDemos\Common\Scissors.FeatureCenter.Modules.LabelEditorDemos.csproj">
<Project>{fe0c4487-711a-4d8d-94e6-c3391eaeca3c}</Project>
<Name>Scissors.FeatureCenter.Modules.LabelEditorDemos</Name>
</ProjectReference>
<ProjectReference Include="..\demos\FeatureCenter\src\Modules\LabelEditorDemos\Contracts\Scissors.FeatureCenter.Modules.LabelEditorDemos.Contracts.csproj">
<Project>{d643979d-0e7c-416b-9251-3350314da37a}</Project>
<Name>Scissors.FeatureCenter.Modules.LabelEditorDemos.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\demos\FeatureCenter\src\Modules\LabelEditorDemos\Win\Scissors.FeatureCenter.Modules.LabelEditorDemos.Win.csproj">
<Project>{324ba4b1-0c4b-48fb-a33c-fb1554a7a744}</Project>
<Name>Scissors.FeatureCenter.Modules.LabelEditorDemos.Win</Name>
</ProjectReference>
<ProjectReference Include="..\Scissors.FeatureCenter.Module.Win\Scissors.FeatureCenter.Module.Win.csproj">
<Project>{7964F87D-BC5D-4C4E-8B2F-71E89739AA97}</Project>
<Name>Scissors.FeatureCenter.Module.Win</Name>
</ProjectReference>
<ProjectReference Include="..\Scissors.FeatureCenter.Module\Scissors.FeatureCenter.Module.csproj">
<Project>{5F15837D-D1E5-44DC-92F0-4F2EBE9C3F8D}</Project>
<Name>Scissors.FeatureCenter.Module</Name>
</ProjectReference>
<ProjectReference Include="..\src\Modules\InlineEditForms\Win\Scissors.ExpressApp.InlineEditForms.Win.csproj">
<Project>{230DACB5-9303-4196-86E3-65203D773D9B}</Project>
<Name>Scissors.ExpressApp.InlineEditForms.Win</Name>
</ProjectReference>
<ProjectReference Include="..\src\Modules\LabelEditor\Contracts\Scissors.ExpressApp.LabelEditor.Contracts.csproj">
<Project>{d707bf95-6819-475e-aaae-b89eb7be0a5e}</Project>
<Name>Scissors.ExpressApp.LabelEditor.Contracts</Name>
</ProjectReference>
<ProjectReference Include="..\src\Modules\LabelEditor\Win\Scissors.ExpressApp.LabelEditor.Win.csproj">
<Project>{2e3e1bd8-2eaf-49e1-9d61-17d5cc3a207b}</Project>
<Name>Scissors.ExpressApp.LabelEditor.Win</Name>
</ProjectReference>
<ProjectReference Include="..\src\Scissors.ExpressApp.Win\Scissors.ExpressApp.Win.csproj">
<Project>{dd958dad-2a51-4dc1-8472-ae925ac1c4a2}</Project>
<Name>Scissors.ExpressApp.Win</Name>
</ProjectReference>
<ProjectReference Include="..\src\Scissors.ExpressApp\Scissors.ExpressApp.csproj">
<Project>{2ce62ff7-23d7-4c81-99a6-19d8e5889668}</Project>
<Name>Scissors.ExpressApp</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="DevExpress.ExpressApp.Images" Version="17.2.7" />
<PackageReference Include="DevExpress.ExpressApp.Validation.Win">
<Version>17.2.7</Version>
</PackageReference>
<PackageReference Include="DevExpress.ExpressApp.Win" Version="17.2.7" />
<PackageReference Include="DevExpress.ExpressApp.Xpo" Version="17.2.7" />
<PackageReference Include="DevExpress.ExpressApp.Images" Version="17.2.7" />
<PackageReference Include="DevExpress.XtraReports" Version="17.2.7" />
</ItemGroup>
<Import Project="..\Scissors.FeatureCenter.Win.Shared\Scissors.FeatureCenter.Win.Shared.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Now we need to remove the Win
reference and replace it with the Win10
one:
The next step is to use other API's for the Win10 projects to specify the paths. For this we add a reference to the Windows.winmd which is located under C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.WinMD
. So Add a reference, switch to browse, select all files and locate it:
Then I suddenly got stuck. Hm in my last test this was working, but now I get this error:
So I found out that I needed to follow the instructions right, install the Anniversary SDK (minumum target SDK) Windows 10 SDK (ver. 10.0.14393.795) and add the following assemblies:
On all *.winmd
files I made sure so set the copy local
option to false.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
.
.
.
<ItemGroup>
<Reference Include="System.Runtime.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.WindowsRuntime.UI.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.UI.Xaml.dll</HintPath>
</Reference>
<Reference Include="Windows, Version=255.255.255.255, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.WinMD</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Windows.Foundation.FoundationContract">
<HintPath>..\..\..\..\Program Files (x86)\Windows Kits\10\References\Windows.Foundation.FoundationContract\2.0.0.0\Windows.Foundation.FoundationContract.winmd</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Windows.Foundation.UniversalApiContract">
<HintPath>..\..\..\..\Program Files (x86)\Windows Kits\10\References\Windows.Foundation.UniversalApiContract\3.0.0.0\Windows.Foundation.UniversalApiContract.winmd</HintPath>
<Private>False</Private>
</Reference>
</ItemGroup>
.
.
.
</Project>
I build the project Scissors.FeatureCenter.Package
, aaaand it worked! :)
So let's ajust some stuff so we get the thing running inside the package.
Adjustments to the code
First of all let's change some namespaces so we can modify our target projects with ease:
Go to the properties pane of the shared project and adjust it to Scissors.FeatureCenter.Win
(your win namespace).
If you wonder where this is stored: It's in a seperate msbuild file called
Scissors.FeatureCenter.Win.Shared.projitems
.
Go to the Properties pane of the Win10 project and adjust It's default namespace as well to Scissors.FeatureCenter.Win
.
In msbuild this property is called
RootNamespace
so you can add this if you like by hand<RootNamespace>Scissors.FeatureCenter.Win</RootNamespace>
Ready to rumble! The nature of Shared projects allow us to add code in our specific assemblies and just "extend" the classes. Think like all files in the Shared project are linked into the target project. That means we can use partial classes and methods to extend the shared project.
Add a partial class that matches your WinApplication
and adjust the following paths:
C:\F\git\Scissors.FeatureCenter\Scissors.FeatureCenter.Win10\FeatureCenterWindowsFormsApplication.cs
:
using System;
using System.IO;
using System.Linq;
using DevExpress.ExpressApp.Win;
namespace Scissors.FeatureCenter.Win
{
public partial class FeatureCenterWindowsFormsApplication : WinApplication
{
protected override string GetDcAssemblyFilePath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName, DcAssemblyFileName);
protected override string GetModelAssemblyFilePath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName, ModelAssemblyFileName);
protected override string GetModelCacheFileLocationPath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName);
protected override string GetModulesVersionInfoFilePath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName, ModulesVersionInfoFileName);
protected override void OnCustomGetUserModelDifferencesPath(CustomGetUserModelDifferencesPathEventArgs args)
=> args.Path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName);
}
}
This will tell XAF where to find or store all the files that are generated by XAF. Let's run with the debugger and look where it's placed the files:
C:\Users\mgrun\AppData\Local\Packages\Scissors.FeatureCenter.Win_ncze720tdpmp2\LocalState\Scissors.FeatureCenter
One is missing, the Tracing.LocalUserAppDataPath
. So let's get into Program.cs
and add a partial method:
C:\F\git\Scissors.FeatureCenter\Scissors.FeatureCenter.Win.Shared\Program.cs
:
using System;
using System.Windows.Forms;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Security;
using DevExpress.ExpressApp.Validation;
using DevExpress.ExpressApp.Validation.Win;
using DevExpress.ExpressApp.Xpo;
using Scissors.ExpressApp.InlineEditForms.Win;
namespace Scissors.FeatureCenter.Win
{
static partial class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
#if EASYTEST
DevExpress.ExpressApp.Win.EasyTest.EasyTestRemotingRegistration.Register();
#endif
EditModelPermission.AlwaysGranted = System.Diagnostics.Debugger.IsAttached;
InitializeTracing();
var winApplication = new FeatureCenterWindowsFormsApplication();
InMemoryDataStoreProvider.Register();
winApplication.ConnectionString = InMemoryDataStoreProvider.ConnectionString;
#if DEBUG
if(System.Diagnostics.Debugger.IsAttached && winApplication.CheckCompatibilityType == CheckCompatibilityType.DatabaseSchema)
{
winApplication.DatabaseUpdateMode = DatabaseUpdateMode.UpdateDatabaseAlways;
}
#endif
try
{
winApplication.Modules.Add(new ValidationModule());
winApplication.Modules.Add(new ValidationWindowsFormsModule());
winApplication.Modules.Add(new InlineEditFormsWindowsFormsModule());
winApplication.Setup();
winApplication.Start();
}
catch(Exception e)
{
winApplication.HandleException(e);
}
}
static partial void InitializeTracing();
}
}
C:\F\git\Scissors.FeatureCenter\Scissors.FeatureCenter.Win10\Program.cs
:
using System;
using System.IO;
using System.Linq;
using DevExpress.Persistent.Base;
namespace Scissors.FeatureCenter.Win
{
static partial class Program
{
static partial void InitializeTracing()
{
Tracing.LogName = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, FeatureCenterWindowsFormsApplication.APP_NAME, "logs", "eXpressAppFramework");
if(!Directory.Exists(Path.GetDirectoryName(Tracing.LogName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(Tracing.LogName));
}
Tracing.Initialize();
}
}
}
Don't forget to adjust the one in the classic desktop winforms world.
C:\F\git\Scissors.FeatureCenter\Scissors.FeatureCenter.Win\Program.cs
:
using System;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using DevExpress.Persistent.Base;
namespace Scissors.FeatureCenter.Win
{
static partial class Program
{
static partial void InitializeTracing()
{
Tracing.LogName = Path.Combine(Application.UserAppDataPath, FeatureCenterWindowsFormsApplication.APP_NAME, "logs", "eXpressAppFramework");
if(!Directory.Exists(Path.GetDirectoryName(Tracing.LogName)))
{
Directory.CreateDirectory(Path.GetDirectoryName(Tracing.LogName));
}
Tracing.Initialize();
}
}
}
Let's run again and look if we get a log file. Yeah!
Creating a Release Package and let the Windows App Certification Kit run
- Switch to
Release
mode. - Rebuild the solution.
- Select the
Package
project. - In the menu select
Project/Store/Create App Packages...
- Select no (we don't want to publish to the store yet)
- Hit Create
- The package get's created
Now let's launch the Windows App Certification Kit
. This may take a while...
The Validation Result is succeeded!
Now we can install the package by double-clicking the package (make sure you actived the developer mode on your Windows 10 machine).
It's possible that you need to add the developer certificate to your machine (with the
Add-AppDevPackage.ps1
powershell script).
If you got a real developer account this isn't necessary.
Bonus-Part: Prebuilding the ModelAssembly and cache files
Once we have a Shared
project in place we can build a additional command line program that sets up our WinApplication and builds the caches and ModelAssembly.dll's we could later pack into our project directory.
Add a Console App
called Scissors.FeatureCenter.Cli
.
Add a reference to the shared project
as for the other two projects:
Add a class called CliProgram
:
using System;
using System.IO;
using System.Linq;
using DevExpress.ExpressApp.Validation;
using DevExpress.ExpressApp.Validation.Win;
using DevExpress.ExpressApp.Xpo;
using Scissors.ExpressApp.InlineEditForms.Win;
namespace Scissors.FeatureCenter.Win
{
static class CliProgram
{
static int Main(string[] args)
{
Console.WriteLine("Generating caches");
using(var winApplication = new FeatureCenterWindowsFormsApplication())
{
try
{
if(Directory.Exists(winApplication.PreCompileOutputDirectory))
{
Directory.Delete(winApplication.PreCompileOutputDirectory, true);
}
Directory.CreateDirectory(winApplication.PreCompileOutputDirectory);
InMemoryDataStoreProvider.Register();
winApplication.ConnectionString = InMemoryDataStoreProvider.ConnectionString;
winApplication.SplashScreen = null;
winApplication.Modules.Add(new ValidationModule());
winApplication.Modules.Add(new ValidationWindowsFormsModule());
winApplication.Modules.Add(new InlineEditFormsWindowsFormsModule());
winApplication.Setup();
}
catch(Exception e)
{
var color = Console.ForegroundColor;
try
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Error:");
Console.WriteLine(new string('=', Console.BufferWidth));
Console.WriteLine(e.ToString());
return 1;
}
finally
{
Console.ForegroundColor = color;
}
}
Console.WriteLine($"Caches created at '{winApplication.PreCompileOutputDirectory}'");
Console.WriteLine("Caches completed");
return 0;
}
}
}
}
Of course thats not that very DRY (I'll get into this more in another best practices post, for example with an
ApplicationBuilder
). But it will work for now.
We need to add another partial FeatureCenterWindowsFormsApplication
class, so we can control the output of the files generated by XAF:
using System;
using System.IO;
using System.Linq;
using DevExpress.ExpressApp.Win;
namespace Scissors.FeatureCenter.Win
{
public partial class FeatureCenterWindowsFormsApplication : WinApplication
{
public string PreCompileOutputDirectory => Path.Combine(Path.GetDirectoryName(GetType().Assembly.Location), "PreCompile");
protected override string GetDcAssemblyFilePath()
=> Path.Combine(PreCompileOutputDirectory, DcAssemblyFileName);
protected override string GetModelAssemblyFilePath()
=> Path.Combine(PreCompileOutputDirectory, ModelAssemblyFileName);
protected override string GetModelCacheFileLocationPath()
=> PreCompileOutputDirectory;
protected override string GetModulesVersionInfoFilePath()
=> Path.Combine(PreCompileOutputDirectory, ModulesVersionInfoFileName);
}
}
Let's have a look:
Awesome, now we need to package them into the Win10 (you also can do this in the normal full framework version) project:
Add all the precompiled assemblies as link into the Win10 project (Add existing item) and make sure you use the Release build:
Make sure they are copied to the output directory by setting the Copy if newer
flag, and mark them as content
.
Change the FeatureCenterWindowsFormsApplication
in the Win10
project as following:
using System;
using System.IO;
using System.Linq;
using DevExpress.ExpressApp.Win;
namespace Scissors.FeatureCenter.Win
{
public partial class FeatureCenterWindowsFormsApplication : WinApplication
{
#if DEBUG
protected override string GetDcAssemblyFilePath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName, DcAssemblyFileName);
protected override string GetModelAssemblyFilePath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName, ModelAssemblyFileName);
protected override string GetModelCacheFileLocationPath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName);
protected override string GetModulesVersionInfoFilePath()
=> Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName, ModulesVersionInfoFileName);
#else
string OutputDirectory => Path.GetDirectoryName(GetType().Assembly.Location);
protected override string GetDcAssemblyFilePath()
=> Path.Combine(OutputDirectory, DcAssemblyFileName);
protected override string GetModelAssemblyFilePath()
=> Path.Combine(OutputDirectory, ModelAssemblyFileName);
protected override string GetModelCacheFileLocationPath()
=> OutputDirectory;
protected override string GetModulesVersionInfoFilePath()
=> Path.Combine(OutputDirectory, ModulesVersionInfoFileName);
#endif
protected override void OnCustomGetUserModelDifferencesPath(CustomGetUserModelDifferencesPathEventArgs args)
=> args.Path = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, ApplicationName);
}
}
So we tell XAF to look at the exe dir for the files. Of course you can change this for any location you like to put them.
Rebuild an run the package project without debugger:
There is overhead from recording the video.
In reality it's like instant, you almost can't see the splash screen.
Holy moly! I never saw an XAF applcation start that quick!
Uff this was a long post. And it isn't production ready yet. But with the help of a little bakery I'll be able to put this thing into the Windows-Store!
As always you can look at the progess and the project on github. This time i tagged the post if people like to see the state as it was when writing this post.
Comments
Kirsten Greed 1 Dec 2018 20:26
Hi Manuel, I am going to try this out! There is a typo "Desktop Bride"
Thank you
Your comment will appear in a few minutes.
Kirsten Greed 9 Dec 2018 18:10
Fantastic post! I actually got XAF into the Windows Store at last. A few adventures on the way with shared projects..
Thank you
Your comment will appear in a few minutes.
Thank you
Your comment will appear in a few minutes.