Skip to content

Commit

Permalink
[xaml] fix x:Array and x:Double in Release mode (#14546)
Browse files Browse the repository at this point in the history
Fixes: #9422
Context: https://github.com/dotnet/maui/blob/51df629f946122945cee8f57baed80eb48e45c4e/src/Controls/src/Core/Properties/AssemblyInfo.cs#L79

In `Microsoft.Maui.Core.dll`, the default `x` namespace is defined as:

    [assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2009/xaml", "System", AssemblyName = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]

The problem being that in apps on iOS and Android where
`PublishTrimmed` is `true`, `mscorlib.dll` will get trimmed away and
callsites will use `System.Private.CoreLib.dll` instead.

This is very much related to the issue fixed in 880ce09.

Unfortunately, my fix wasn't sufficient, because the `AssemblyName`
name in this case is the full name:

    AssemblyName = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

To solve the issue, let's also check for `StartsWith("mscorlib,")`.

We *could* add a new `XmlnsDefinition`, but this doesn't feel right:

    [assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2009/xaml", "System", AssemblyName = "System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]

It doesn't make sense for a "private" assembly to appear in XAML
intellisense.

I also moved these tests to a new `XamlTests` class, as it didn't
really make sense to put them with `RadioButton` tests.

Note that these new tests wouldn't fail until we start running device
tests in `Release` mode:

#14392
  • Loading branch information
jonathanpeppers authored Apr 17, 2023
1 parent 48d0294 commit f939049
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/Controls/src/Xaml/XmlTypeXamlExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static class XmlTypeXamlExtensions
potentialTypes.Add(new(typeName, xmlnsDefinitionAttribute.ClrNamespace, xmlnsDefinitionAttribute.AssemblyName));

// As a fallback, for assembly=mscorlib try assembly=System.Private.CoreLib
if (xmlnsDefinitionAttribute.AssemblyName == "mscorlib")
if (xmlnsDefinitionAttribute.AssemblyName == "mscorlib" || xmlnsDefinitionAttribute.AssemblyName.StartsWith("mscorlib,", StringComparison.Ordinal))
{
potentialTypes.Add(new(typeName, xmlnsDefinitionAttribute.ClrNamespace, "System.Private.CoreLib"));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
<Compile Remove="**\*.Windows.cs" />
</ItemGroup>
<ItemGroup>
<Compile Update="Elements\RadioButton\RadioButtonUsing.xaml.cs">
<Compile Update="Xaml\RadioButtonUsing.xaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,34 +41,5 @@ public async Task IsCheckedInitializesCorrectly(bool isChecked)
Assert.Equal(expectedValue, valuesSecond.PlatformViewValue);
}
#endif

[Fact("Parsed XAML can use mscorlib")]
public void Namespace_mscorlib_Parsed()
{
var page = new ContentPage();
page.LoadFromXaml(
"""
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<RadioButton>
<RadioButton.Value>
<sys:Int32>1</sys:Int32>
</RadioButton.Value>
</RadioButton>
</ContentPage>
""");
Assert.IsType<RadioButton>(page.Content);
Assert.Equal(1, ((RadioButton)page.Content).Value);
}

[Fact("Compiled XAML can use mscorlib")]
public void Namespace_mscorlib_Compiled()
{
var page = new RadioButtonUsing();
Assert.IsType<RadioButton>(page.Content);
Assert.Equal(1, ((RadioButton)page.Content).Value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
x:Class="Microsoft.Maui.DeviceTests.RadioButtonUsing">
<ContentPage.Resources>
<ResourceDictionary>
<x:Array Type="{x:Type x:String}" x:Key="MyArray">
<x:String>Foo</x:String>
<x:String>Bar</x:String>
<x:String>Baz</x:String>
</x:Array>
<x:Double x:Key="MyNumber">42</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<RadioButton>
<RadioButton.Value>
Expand Down
98 changes: 98 additions & 0 deletions src/Controls/tests/DeviceTests/Xaml/XamlTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;
using Xunit;

namespace Microsoft.Maui.DeviceTests
{
public class XamlTests
{
[Fact("Parsed XAML can use mscorlib")]
public void Namespace_mscorlib_Parsed()
{
var page = new ContentPage();
page.LoadFromXaml(
"""
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<RadioButton>
<RadioButton.Value>
<sys:Int32>1</sys:Int32>
</RadioButton.Value>
</RadioButton>
</ContentPage>
""");
Assert.IsType<RadioButton>(page.Content);
Assert.Equal(1, ((RadioButton)page.Content).Value);
}

[Fact("Compiled XAML can use mscorlib")]
public void Namespace_mscorlib_Compiled()
{
var page = new RadioButtonUsing();
Assert.IsType<RadioButton>(page.Content);
Assert.Equal(1, ((RadioButton)page.Content).Value);
}

[Fact("Parsed XAML can use x:Array")]
public void x_Array_Parsed()
{
var page = new ContentPage();
page.LoadFromXaml(
"""
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ContentPage.Resources>
<ResourceDictionary>
<x:Array Type="{x:Type x:String}" x:Key="MyArray">
<x:String>Foo</x:String>
<x:String>Bar</x:String>
<x:String>Baz</x:String>
</x:Array>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
""");
string[] array = page.Resources["MyArray"] as string[];
Assert.Equal(new[] { "Foo", "Bar", "Baz" }, array);
}

[Fact("Compiled XAML can use x:Array")]
public void x_Array_Compiled()
{
var page = new RadioButtonUsing();
string[] array = page.Resources["MyArray"] as string[];
Assert.Equal(new[] { "Foo", "Bar", "Baz" }, array);
}

[Fact("Parsed XAML can use x:Double")]
public void x_Double_Parsed()
{
var page = new ContentPage();
page.LoadFromXaml(
"""
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<ContentPage.Resources>
<ResourceDictionary>
<x:Double x:Key="MyNumber">42</x:Double>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
""");
Assert.Equal(42d, page.Resources["MyNumber"]);
}

[Fact("Compiled XAML can use x:Double")]
public void x_Double_Compiled()
{
var page = new RadioButtonUsing();
Assert.Equal(42d, page.Resources["MyNumber"]);
}
}
}

0 comments on commit f939049

Please sign in to comment.