Throws a XamlParseException on duplicate x:Key on RDs. This will find
duplicate in xaml, but duplicates can still happen if the RD is modified
in code. Those dupes are already detectd at runtime.
- helps, but doesn't fixes, #3512
Some links about design-time builds:
- https://github.com/dotnet/project-system/blob/master/docs/design-time-builds.md
- https://daveaglick.com/posts/running-a-design-time-build-with-msbuild-apis
In Visual Studio 2017 (Windows), a "design-time" build is what drives
Intellisense in cases such as using `x:Name` in XAML (or
`Resource.designer.cs` in a plain Xamarin.Android app). Improving our
"design-time" build speed will improve general performance in the IDE
such as project load and how long Intellisense takes to update. Since
XamlC is not needed during a design-time build, it is an "easy-win" to
just disable it. XamlC can take a bit of time for projects with a lot
of XAML.
This might also help with: https://github.com/xamarin/Xamarin.Forms/issues/3004
Although we should probably not do anything to specifically support
NCrunch; hopefully, NCrunch is running under the context of a
design-time build.
* [XamlG] builds incrementally, add MSBuild integration tests
Context: https://github.com/xamarin/Xamarin.Forms/pull/2230
The main performance problem with the collection of MSBuild targets in
`Xamarin.Forms.targets` is they don't build incrementally. I addressed
this with `XamlC` using a "stamp" file; however, it is not quite so
easy to setup the same thing with `XamlG`.
They way "incremental" builds are setup in MSBuild, is by specifying
the `Inputs` and `Outputs` of a `<Target />`. MSBuild will partially
build a target when some outputs are not up to date, and skip it
entirely if they are all up to date.
The best docs I can find on MSBuild incremental builds:
https://msdn.microsoft.com/en-us/library/ms171483.aspx
Unfortunately a few things had to happen to make this work for
`XamlG`:
- Define a new target `_FindXamlGFiles` that is invoked before `XamlG`
- `_FindXamlGFiles` defines the `_XamlGInputs` and `_XamlGOutputs`
`<ItemGroup />`'s
- `_FindXamlGFiles` must also define `<Compile />` and `<FileWrites />`,
in case the `XamlG` target is skipped
- `XamlGTask` now needs to get passed in a list of `OutputFiles`,
since we have computed these paths ahead of time
- `XamlGTask` should validate the lengths of `XamlFiles` and
`OutputFiles` match, used error message from MSBuild proper:
a691a44f0e/src/Tasks/Copy.cs (L505)
`XamlG` now builds incrementally!
To give some context on how much improvement we can see with build
times, consider the following command:
msbuild Xamarin.Forms.ControlGallery.Android/Xamarin.Forms.ControlGallery.Android.csproj
If you run it once, it will take a while--this change will not improve
the first build. On the second build with the exact same command, it
*should* be much faster.
Before this commit, the second build on my machine takes:
40.563s
After the change:
23.692s
`XamlG` has cascading impact on build times when it isn't built
incrementally:
- The C# assembly always changes
- Hence, `XamlC` will always run
- Hence, `GenerateJavaStubs` will always run
- Hence, `javac.exe` and `dx.jar` will always run
I am making other improvements like this in Xamarin.Android itself,
that will further improve these times, such as:
https://github.com/xamarin/xamarin-android/pull/1693
~~ New MSBuild Integration Tests ~~
Added some basic MSBuild testing infrastructure:
- Tests write project files to `bin/Debug/temp/TestName`
- Each test has an `sdkStyle` flag for testing the new project system
versus the old one
- `[TearDown]` deletes the entire directory, with a retry for
`IOException` on Windows
- Used the `Microsoft.Build.Locator` NuGet package for locating
`MSBuild.exe` on Windows
- These tests take 2-5 seconds each
So for example, the simplest test, `BuildAProject` writes to
`Xamarin.Forms.Xaml.UnitTests\bin\Debug\temp\BuildAProject(False)\test.csproj`:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
<OutputType>Library</OutputType>
<OutputPath>bin\Debug</OutputPath>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="System" />
<Reference Include="Xamarin.Forms.Core.dll">
<HintPath>..\..\Xamarin.Forms.Core.dll</HintPath>
</Reference>
<Reference Include="Xamarin.Forms.Xaml.dll">
<HintPath>..\..\Xamarin.Forms.Xaml.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\..\..\.nuspec\Xamarin.Forms.targets" />
<ItemGroup>
<EmbeddedResource Include="MainPage.xaml" />
</ItemGroup>
</Project>
Invokes `msbuild`, and checks the intermediate output for files being
generated.
Tested scenarios:
- Build a simple project
- Build, then build again, and make sure targets were skipped
- Build, then clean, make sure files are gone
- Build, with linked files
- Design-time build
- Call `UpdateDesignTimeXaml` directly
- Build, add a new file, build again
- Build, update timestamp on a file, build again
- XAML file with random XML content
- XAML file with invalid XML content
- A general `EmbeddedResource` that shouldn't go through XamlG
Adding these tests found a bug! `IncrementalClean` was deleting
`XamlC.stamp`. I fixed this by using `<ItemGroup />`, which will be
propery evaluated even if the target is skipped.
~~ Other Changes ~~
- `FilesWrite` is actually supposed to be `FileWrites`, see canonical
source of how `Clean` works and what `FileWrites` is here:
https://github.com/Microsoft/msbuild/issues/2408#issuecomment-321082997
- Moved `DummyBuildEngine` into `MSBuild` directory--makes sense?
maybe don't need to?
- Added a `XamlGDifferentInputOutputLengths` test to check the error
message
- Expanded `DummyBuildEngine` so you can assert against log messages
- Changed a setting in `.Xamarin.Forms.Android.sln` so the unit test
project is built
- My VS IDE monkeyed with a few files, and I kept any *good* (or
relevant) changes: `Xamarin.Forms.UnitTests.csproj`,
`Xamarin.Forms.Xaml.UnitTests\app.config`, etc.
There were some checks for `%(TargetPath)` being blank in the C# code
of `XamlGTask`. In that case it was using `Path.GetRandomFileName`,
but we can't do this if we are setting up inputs and outputs for
`XamlG`. I presume this is from the designer and/or design-time builds
before `DependsOnTargets="PrepareResourceNames"` was added. I tested
design-time builds in VS on Windows, and `$(TargetPath)` was set. To
be sure we don't break anything here, I exclude inputs to `XamlG` if
`%(TargetPath)` is somehow blank.
See relevant MSBuild code for `%(TargetPath)` here:
0515178090/src/Tasks/Microsoft.Common.CurrentVersion.targets (L2822)
~~ Future changes ~~
CssG needs the exact same setup, as it was patterned after `XamlG`.
This should probably be done in a future PR.
* [msbuild] improved lookup of Xamarin.Forms.targets in integration tests
Context: https://devdiv.visualstudio.com/DevDiv/_build?buildId=1717939
Context: https://devdiv.visualstudio.com/DevDiv/_build?buildId=1718306
It looks like the VSTS builds for release branches are running tests
in a staging directory. This means we can't reliably import
`Xamarin.Forms.targets` as what was working locally in the
Xamarin.Forms source tree.
So to fix this:
- Look for `.nuspec/Xamarin.Forms.targets`, at the default location
and then using the `BUILD_SOURCESDIRECTORY` environment variable as
a fallback
- Copy all `*.targets` files to the test directory
- Our `*.csproj` files under test can import the file from there.
We have to copy the targets files here to be sure that MSBuild can
load `Xamarin.Forms.Build.Tasks.dll`, which is also referenced by the
unit tests.
I also made the tests abort earlier if they can't find
`Xamarin.Forms.targets`.
* Call ChangeVisualState when new states are added so element is in correct
state when loaded from XAML; fixes#2625
* Fix build for UI test projects
* fix uitest build
* Added OnPlatform markup extension supporting iOS/Android/UWP for #2608
* Add Default and Other properties to OnPlatformExtension
This allows setting a default value for unknown platforms, as well
as specify values for arbitrary platforms by using a named parameter
like syntax:
`{OnPlatform Android=15, iOS=10, UWP=12, Default=11, Other=Tizen:20}`
The `Other` supports multiple semi-colon separated values. By using
this format, we can make the string more concise than if we used `=`
which would have to be escaped in quotes. For example:
`{OnPlatform Default=10, Other=Tizen:22;Xbox:20;Switch=25;PlayStation=22}`
Added unit tests that verify all the supported combinations.
* Add OnIdiomExtension
The extension allows the following syntax:
`{OnIdiom Phone=23, Tablet=25, Desktop=26, TV=30, Watch=10, Default=20}`
At least one value or `Default` must be specified. `Default` is returned
whenever the specific idiom was not specified.
* Add missing known platforms and return Default if missing
Add all strings that are provided in `Device`.
Convert individual asserts into test cases for better reporting.
Also, whenever a matching platform value isn't specified, return Default
instead of null.
* Turn OnIdiom asserts into test cases
This makes for easier to read, document and report tests.
* Add missing platforms to null check
* Make Default the content property
* Perform type conversion as expected by XamlC
Leverage the conversion that is used elsewhere, to return a
properly typed object that can be assigned directly to the
property. Update tests with typed values since now we get
integers, rather than strings out of the parser.
* Add Converter/ConverterParameter support
* Message should state that the value must be non-null
* Remove Unsupported idiom since it's not useful to set
You can use Default instead.
* Use new GetService<T> extension method for conciseness
* Don't fail if service provider is null
* Remove Other from OnPlatformExtension
As suggested, this might come back in the future in some other form.
* [Xaml] open non-generic FindByName()
* [Xaml[C]] Only set the namescope when it's different
avoid setting the NamesCope if it's the same as the parent.
Also provide an IReferenceProvider for markup extension that need to
replicate the x:Reference behavior.
* [XamlC] x:DataType in default xmlns
* [XamlC] meaningful error on missing property
throw a readable exception when part of a compiled binding path is
missing.
- fixes#2517
* Disable AndroidUseLatestPlatformSdk in VS so VS stops auto-updating Android projects;
Remove XF.targets imports from projects which don't need it;
Make XF.targets imports conditional on existence of XFBT DLL in VS to avoid errors
* More consistent check for VS
* Apply nicer VS check logic to Xamarin.Forms.Xaml.UnitTests.csproj
* Fix missing "'"
* Re-add XF.targets imports to PagesGallery native projects
* [C/XamlC] BindingMode.OneTime
Bindings with mode == OneTime:
- are only applied when the BindingContext changes
- do not subscribe to INPC
if the Binding is compiled and the mode explicitely set in the
`{Binding}` Markup extension, the setters and handlers aren't even
created.
- fixes#1686
* update docs
* [Xaml] let the previewer know the asm
in addition to the resourcePath, tell the previewer the assembly in
which we're looking for the resource.
* fix docs