Skip to content

Commit

Permalink
Merge pull request #3888 from unoplatform/dev/djo/gsr-instance
Browse files Browse the repository at this point in the history
Adjust Xaml code generation
  • Loading branch information
davidjohnoliver authored Sep 24, 2020
2 parents 26d0f79 + 5035639 commit 1a0ee79
Show file tree
Hide file tree
Showing 21 changed files with 638 additions and 295 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace Uno.UI.SourceGenerators.XamlGenerator
internal partial class XamlCodeGeneration
{
internal const string ParseContextPropertyName = "__ParseContext_";
internal const string ParseContextPropertyType = "global::Uno.UI.Xaml.XamlParseContext";

private readonly string[] _xamlSourceFiles;
private readonly string[] _xamlSourceLinks;
Expand Down Expand Up @@ -498,7 +499,7 @@ private string GenerateGlobalResources(IEnumerable<XamlFileDefinition> files, Xa
writer.AppendLineInvariant("private static bool _stylesRegistered;");
writer.AppendLineInvariant("private static bool _dictionariesRegistered;");

using (writer.BlockInvariant("internal static global::Uno.UI.Xaml.XamlParseContext {0} {{get; }} = new global::Uno.UI.Xaml.XamlParseContext()", ParseContextPropertyName))
using (writer.BlockInvariant("internal static {0} {1} {{get; }} = new {0}()", ParseContextPropertyType, ParseContextPropertyName))
{
writer.AppendLineInvariant("AssemblyName = \"{0}\",", _projectInstance.GetPropertyValue("AssemblyName"));
}
Expand Down

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions src/Uno.UI.Tests.ViewLibrary/TestInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Uno.UI.Tests.ViewLibrary
{
// This type should only be created by the Test_Dictionary_Initializer dictionary
public class TestInitializer
{
public static bool IsInitialized { get; private set; }

public TestInitializer()
{
IsInitialized = true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:ext="using:Uno.UI.Tests.ViewLibrary">
<!--This dictionary should only be referenced by the Test_Control_With_Initializer control-->
<ext:TestInitializer x:Key="TestInitializer" />
</ResourceDictionary>
5 changes: 1 addition & 4 deletions src/Uno.UI.Tests.ViewLibrary/Uno.UI.Tests.ViewLibrary.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@
<Import Project="..\Common.targets" />

<ItemGroup Condition="'$(BuildingInsideUnoSourceGenerator)'!=''">
<Page Include="Themes\Generic.xaml" />
<Page Include="Themes\MyExtControl.xaml" />
<Page Include="Themes\More\Test_Dictionary_Abs.xaml" />
<Page Include="Themes\More\Test_Dictionary_Merged.xaml" />
<Page Include="Themes\**\*.xaml" />
</ItemGroup>

<ItemGroup>
Expand Down
17 changes: 17 additions & 0 deletions src/Uno.UI.Tests/App/Xaml/Test_Control_With_Initializer.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<UserControl x:Class="Uno.UI.Tests.App.Xaml.Test_Control_With_Initializer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.Tests.App.Xaml"
xmlns:views="using:Uno.UI.Tests.App.Views"
xmlns:ext="using:Uno.UI.Tests.ViewLibrary"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<!--This control should only be created by the When_Needs_Eager_Materialization() test-->
<UserControl.Resources>
<ResourceDictionary Source="ms-appx:///Uno.UI.Tests.ViewLibrary/Themes/More/Test_Dictionary_Initializer.xaml" />
</UserControl.Resources>

<Grid>
</Grid>
</UserControl>
32 changes: 32 additions & 0 deletions src/Uno.UI.Tests/App/Xaml/Test_Control_With_Initializer.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Uno.UI.Tests.App.Views;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace Uno.UI.Tests.App.Xaml
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class Test_Control_With_Initializer : UserControl
{

public Test_Control_With_Initializer()
{
this.InitializeComponent();
}
}
}
2 changes: 2 additions & 0 deletions src/Uno.UI.Tests/App/Xaml/Test_Dictionary.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,6 @@
<TextBlock Foreground="{ThemeResource ResourceKeyLocalReference}" />
</Grid>
</ControlTemplate>
<SolidColorBrush x:Key="Resource With Space In Key"
Color="SlateBlue" />
</ResourceDictionary>
3 changes: 3 additions & 0 deletions src/Uno.UI.Tests/App/Xaml/Test_Page_Other.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,8 @@
x:FieldModifier="public"
Foreground="{StaticResource BituminousColorBrush}" />
</Grid>
<Border x:Name="SpaceInKeyBorder"
x:FieldModifier="public"
Background="{StaticResource Resource With Space In Key}" />
</Grid>
</Page>
14 changes: 1 addition & 13 deletions src/Uno.UI.Tests/Uno.UI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,8 @@
<Page Include="Windows_UI_Xaml\**\*.xaml" />
<Page Include="Windows_UI_Xaml_Data\**\*.xaml" />
<Page Include="Windows_UI_Xaml_Controls\**\*.xaml" />
<Page Include="App\App.xaml" />
<Page Include="App\Xaml\Test_CreateFromString.xaml" />
<Page Include="App\Xaml\Test_Dictionary.xaml" />
<Page Include="App\Xaml\Test_Dictionary_Inner.xaml" />
<Page Include="App\Xaml\Test_Dictionary_Theme.xaml" />
<Page Include="App\Xaml\Test_Dictionary_Isolated.xaml" />
<Page Include="App\Xaml\Test_Dictionary_Isolated_2.xaml" />
<Page Include="App\Xaml\Subclassed_Dictionary.xaml" />
<Page Include="App\**\*.xaml" />
<Page Include="..\SamplesApp\UITests.Shared\Windows_UI_Xaml\Resources\Test_Dictionary_Linked.xaml" Link="App/Linked/Test_Dictionary_Linked.xaml" />
<Page Include="App\Xaml\Test_Control.xaml" />
<Page Include="App\Xaml\Test_MarkupExtension.xaml" />
<Page Include="App\Xaml\Test_Styles.xaml" />
<Page Include="App\Xaml\Test_Page.xaml" />
<Page Include="App\Xaml\Test_Page_Other.xaml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\Uno.UI.RuntimeTests\Helpers\SizeAssertion.cs" Link="Extensions\SizeAssertion.cs" />
Expand Down
17 changes: 17 additions & 0 deletions src/Uno.UI.Tests/Windows_UI_Xaml/Given_ResourceDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Uno.UI.Tests.App.Xaml;
using Uno.UI.Tests.Helpers;
using Uno.UI.Tests.ViewLibrary;
#if !NETFX_CORE
using Uno.UI.Xaml;
#endif
Expand Down Expand Up @@ -684,5 +685,21 @@ public void When_XamlControlsResources()
Assert.IsTrue(xcr.ContainsKey(typeof(Button)));
Assert.IsInstanceOfType(xcr[typeof(Button)], typeof(Style));
}

[TestMethod]
public void When_Needs_Eager_Materialization()
{
Assert.IsFalse(TestInitializer.IsInitialized);
var control = new Test_Control_With_Initializer();
Assert.IsTrue(TestInitializer.IsInitialized);
}

[TestMethod]
public void When_Space_In_Key()
{
var page = new Test_Page_Other();
var border = page.SpaceInKeyBorder;
Assert.AreEqual(Colors.SlateBlue, (border.Background as SolidColorBrush).Color);
}
}
}
32 changes: 32 additions & 0 deletions src/Uno.UI/Helpers/Xaml/SetterHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml;

namespace Uno.UI.Helpers.Xaml
{
[EditorBrowsable(EditorBrowsableState.Never)]
// This is normally called from code generated by the Xaml parser
//
// NOTE: This class' methods may be called often from generated code. It MUST NOT have static state or a static ctor as it impacts the size of the generated code of the call site of this method when using mono's AOT engine.
public static class SetterHelper
{
public static Setter GetPropertySetterWithResourceValue(DependencyProperty dependencyProperty, object key, object context, object defaultValue)
{
return new Setter(dependencyProperty, ProvideSetterValue);

object ProvideSetterValue()
{
if (ResourceResolver.ResolveResourceStatic(key, out var value, context))
{
return value;
}

return defaultValue;
}
}
}
}
26 changes: 26 additions & 0 deletions src/Uno.UI/UI/Xaml/IXamlLazyResourceInitializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging;
using Uno.Diagnostics.Eventing;
using Uno.Extensions;
using Uno.UI.DataBinding;
using Uno.UI.Xaml;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Resources;

namespace Uno.UI
{
/// <summary>
/// Provides initialization logic for resources defined in a ResourceDictionary.
/// </summary>
/// <remarks> Normally only implemented and referenced by Xaml-generated code.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IXamlLazyResourceInitializer
{
object GetInitializedValue(string resourceRetrievalKey);
}
}
26 changes: 26 additions & 0 deletions src/Uno.UI/UI/Xaml/IXamlResourceDictionaryProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging;
using Uno.Diagnostics.Eventing;
using Uno.Extensions;
using Uno.UI.DataBinding;
using Uno.UI.Xaml;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Resources;

namespace Uno.UI
{
/// <summary>
/// Provides lazy initialization for a resource dictionary.
/// </summary>
/// <remarks> Normally only implemented and referenced by Xaml-generated code.</remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public interface IXamlResourceDictionaryProvider
{
ResourceDictionary GetResourceDictionary();
}
}
26 changes: 10 additions & 16 deletions src/Uno.UI/UI/Xaml/ResourceDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public bool HasKey(object key)
/// and can be removed as breaking change later.</remarks>
public bool Insert(object key, object value)
{
Set(key, value);
Set(key, value, throwIfPresent: false);
return true;
}

Expand All @@ -79,18 +79,7 @@ public bool Insert(object key, object value)

public void Clear() => _values.Clear();

public void Add(object key, object value)
{
if (value is ResourceInitializer resourceInitializer)
{
_hasUnmaterializedItems = true;
_values.Add(key, new LazyInitializer(ResourceResolver.CurrentScope, resourceInitializer));
}
else
{
_values.Add(key, value);
}
}
public void Add(object key, object value) => Set(key, value, throwIfPresent: true);

public bool ContainsKey(object key) => ContainsKey(key, shouldCheckSystem: true);
public bool ContainsKey(object key, bool shouldCheckSystem) => _values.ContainsKey(key) || ContainsKeyMerged(key) || ContainsKeyTheme(key)
Expand Down Expand Up @@ -133,11 +122,16 @@ public object this[object key]

return value;
}
set => Set(key, value);
set => Set(key, value, throwIfPresent: false);
}

private void Set(object key, object value)
private void Set(object key, object value, bool throwIfPresent)
{
if (throwIfPresent && _values.ContainsKey(key))
{
throw new ArgumentException("An entry with the same key already exists.");
}

if (value is ResourceInitializer resourceInitializer)
{
_hasUnmaterializedItems = true;
Expand Down Expand Up @@ -299,7 +293,7 @@ private void CopyFrom(ResourceDictionary source)

public global::System.Collections.Generic.ICollection<object> Keys => _values.Keys;

// TODO: this doesn't handle lazy initializers or aliases
// TODO: this doesn't handle lazy initializers or aliases
public global::System.Collections.Generic.ICollection<object> Values => _values.Values;

public void Add(global::System.Collections.Generic.KeyValuePair<object, object> item) => Add(item.Key, item.Value);
Expand Down
7 changes: 4 additions & 3 deletions src/Uno.UI/UI/Xaml/ResourceResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ static ResourceResolver()
/// <summary>
/// Performs a one-time, typed resolution of a named resource, using Application.Resources.
/// </summary>
/// <returns></returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public static T ResolveResourceStatic<T>(object key, object context = null)
{
Expand All @@ -73,9 +72,8 @@ public static T ResolveResourceStatic<T>(object key, object context = null)
}

/// <summary>
/// Performs a one-time, typed resolution of a named resource, using Application.Resources.
/// Performs a one-time resolution of a named resource, using Application.Resources.
/// </summary>
/// <returns></returns>
[EditorBrowsable(EditorBrowsableState.Never)]
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool ResolveResourceStatic(object key, out object value, object context = null)
Expand Down Expand Up @@ -398,4 +396,7 @@ public static object ResolveStaticResourceAlias(string resourceKey, object parse

internal static void UpdateSystemThemeBindings() => MasterDictionary.UpdateThemeBindings();
}



}
39 changes: 39 additions & 0 deletions src/Uno.UI/UI/Xaml/ResourceResolverSingleton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using Microsoft.Extensions.Logging;
using Uno.Diagnostics.Eventing;
using Uno.Extensions;
using Uno.UI.DataBinding;
using Uno.UI.Xaml;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Resources;

namespace Uno.UI
{
/// <summary>
/// A wrapper for <see cref="ResourceResolver"/> methods following the singleton pattern.
/// </summary>
/// <remarks>
/// The motivation is to avoid additional overhead associated with static method calls into types with static state. This is normally
/// only called from Xaml-generated code.
/// </remarks>
[EditorBrowsable(EditorBrowsableState.Never)]
public sealed class ResourceResolverSingleton
{
private static ResourceResolverSingleton _instance;
public static ResourceResolverSingleton Instance => _instance ??= new ResourceResolverSingleton();

[EditorBrowsable(EditorBrowsableState.Never)]
public bool ResolveResourceStatic(object key, out object value, object context) => ResourceResolver.ResolveResourceStatic(key, out value, context);

[EditorBrowsable(EditorBrowsableState.Never)]
public void ApplyResource(DependencyObject owner, DependencyProperty property, object resourceKey, bool isThemeResourceExtension, object context) => ResourceResolver.ApplyResource(owner, property, resourceKey, isThemeResourceExtension, context);

[EditorBrowsable(EditorBrowsableState.Never)]
public object ResolveStaticResourceAlias(string resourceKey, object parseContext) => ResourceResolver.ResolveStaticResourceAlias(resourceKey, parseContext);
}
}
Loading

0 comments on commit 1a0ee79

Please sign in to comment.