Browse Source

Merge branch 'master' into feature/formattedTextBuildGeometry

pull/8326/head
Max Katz 4 years ago
committed by GitHub
parent
commit
fc0ef7f376
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      samples/ControlCatalog.Android/ControlCatalog.Android.csproj
  2. 3
      samples/ControlCatalog.Android/Properties/AndroidManifest.xml
  3. 1
      samples/ControlCatalog.Android/environment.device.txt
  4. 1
      samples/ControlCatalog.Android/environment.emulator.txt
  5. 14
      src/Avalonia.Controls/GridSplitter.cs
  6. 17
      src/Avalonia.Controls/Templates/DataTemplates.cs
  7. 10
      src/Avalonia.Controls/Templates/ITypedDataTemplate.cs
  8. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs
  9. 73
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs
  10. 2
      src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
  11. 2
      src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
  12. 7
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
  13. 8
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs
  14. 113
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs
  15. 19
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs

27
samples/ControlCatalog.Android/ControlCatalog.Android.csproj

@ -9,42 +9,37 @@
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion> <ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
<AndroidPackageFormat>apk</AndroidPackageFormat> <AndroidPackageFormat>apk</AndroidPackageFormat>
<MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver> <MSBuildEnableWorkloadResolver>true</MSBuildEnableWorkloadResolver>
<RuntimeIdentifiers>android-arm64;android-x64</RuntimeIdentifiers>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Remove="Assets\AboutAssets.txt" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<AndroidResource Include="..\..\build\Assets\Icon.png"> <AndroidResource Include="..\..\build\Assets\Icon.png">
<Link>Resources\drawable\Icon.png</Link> <Link>Resources\drawable\Icon.png</Link>
</AndroidResource> </AndroidResource>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release' and '$(TF_BUILD)' == ''"> <PropertyGroup Condition="'$(RunAOTCompilation)'=='' and '$(Configuration)'=='Release' and '$(TF_BUILD)'==''">
<DebugSymbols>False</DebugSymbols>
<UseInterpreter>False</UseInterpreter>
<RunAOTCompilation>True</RunAOTCompilation> <RunAOTCompilation>True</RunAOTCompilation>
</PropertyGroup>
<PropertyGroup Condition="'$(RunAOTCompilation)'=='True'">
<EnableLLVM>True</EnableLLVM> <EnableLLVM>True</EnableLLVM>
<AndroidAotAdditionalArguments>no-write-symbols,nodebug</AndroidAotAdditionalArguments> <AndroidAotAdditionalArguments>no-write-symbols,nodebug</AndroidAotAdditionalArguments>
<AndroidAotMode>Hybrid</AndroidAotMode> <AndroidAotMode>Hybrid</AndroidAotMode>
<AndroidGenerateJniMarshalMethods>True</AndroidGenerateJniMarshalMethods> <AndroidGenerateJniMarshalMethods>True</AndroidGenerateJniMarshalMethods>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(AndroidEnableProfiler)'=='True'">
<EmbedAssembliesIntoApk>False</EmbedAssembliesIntoApk> <IsEmulator Condition="'$(IsEmulator)' == ''">True</IsEmulator>
<RunAOTCompilation>False</RunAOTCompilation> <DebugSymbols>True</DebugSymbols>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Xamarin.AndroidX.AppCompat" Version="1.3.1.3" /> <AndroidEnvironment Condition="'$(IsEmulator)'=='True'" Include="environment.emulator.txt" />
<PackageReference Include="Xamarin.AndroidX.Lifecycle.ViewModel" Version="2.3.1.3" /> <AndroidEnvironment Condition="'$(IsEmulator)'!='True'" Include="environment.device.txt" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" /> <ProjectReference Include="..\..\src\Android\Avalonia.Android\Avalonia.Android.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

3
samples/ControlCatalog.Android/Properties/AndroidManifest.xml

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="auto">
<application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application> <application android:label="ControlCatalog.Android" android:icon="@drawable/Icon"></application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest> </manifest>

1
samples/ControlCatalog.Android/environment.device.txt

@ -0,0 +1 @@
DOTNET_DiagnosticPorts=127.0.0.1:9000,suspend

1
samples/ControlCatalog.Android/environment.emulator.txt

@ -0,0 +1 @@
DOTNET_DiagnosticPorts=10.0.2.2:9001,suspend

14
src/Avalonia.Controls/GridSplitter.cs

@ -221,7 +221,8 @@ namespace Avalonia.Controls
ShowsPreview = showsPreview, ShowsPreview = showsPreview,
ResizeDirection = resizeDirection, ResizeDirection = resizeDirection,
SplitterLength = Math.Min(Bounds.Width, Bounds.Height), SplitterLength = Math.Min(Bounds.Width, Bounds.Height),
ResizeBehavior = GetEffectiveResizeBehavior(resizeDirection) ResizeBehavior = GetEffectiveResizeBehavior(resizeDirection),
Scaling = (VisualRoot as ILayoutRoot)?.LayoutScaling ?? 1,
}; };
// Store the rows and columns to resize on drag events. // Store the rows and columns to resize on drag events.
@ -630,13 +631,17 @@ namespace Avalonia.Controls
{ {
double actualLength1 = GetActualLength(definition1); double actualLength1 = GetActualLength(definition1);
double actualLength2 = GetActualLength(definition2); double actualLength2 = GetActualLength(definition2);
double pixelLength = 1 / _resizeData.Scaling;
double epsilon = pixelLength + LayoutHelper.LayoutEpsilon;
// When splitting, Check to see if the total pixels spanned by the definitions // When splitting, Check to see if the total pixels spanned by the definitions
// is the same as before starting resize. If not cancel the drag. // is the same as before starting resize. If not cancel the drag. We need to account for
// layout rounding here, so ignore differences of less than a device pixel to avoid problems
// that WPF has, such as https://stackoverflow.com/questions/28464843.
if (_resizeData.SplitBehavior == SplitBehavior.Split && if (_resizeData.SplitBehavior == SplitBehavior.Split &&
!MathUtilities.AreClose( !MathUtilities.AreClose(
actualLength1 + actualLength2, actualLength1 + actualLength2,
_resizeData.OriginalDefinition1ActualLength + _resizeData.OriginalDefinition2ActualLength, LayoutHelper.LayoutEpsilon)) _resizeData.OriginalDefinition1ActualLength + _resizeData.OriginalDefinition2ActualLength, epsilon))
{ {
CancelResize(); CancelResize();
@ -798,6 +803,9 @@ namespace Avalonia.Controls
// The minimum of Width/Height of Splitter. Used to ensure splitter // The minimum of Width/Height of Splitter. Used to ensure splitter
// isn't hidden by resizing a row/column smaller than the splitter. // isn't hidden by resizing a row/column smaller than the splitter.
public double SplitterLength; public double SplitterLength;
// The current layout scaling factor.
public double Scaling;
} }
} }

17
src/Avalonia.Controls/Templates/DataTemplates.cs

@ -1,3 +1,4 @@
using System;
using Avalonia.Collections; using Avalonia.Collections;
namespace Avalonia.Controls.Templates namespace Avalonia.Controls.Templates
@ -13,6 +14,22 @@ namespace Avalonia.Controls.Templates
public DataTemplates() public DataTemplates()
{ {
ResetBehavior = ResetBehavior.Remove; ResetBehavior = ResetBehavior.Remove;
Validate += ValidateDataTemplate;
}
private static void ValidateDataTemplate(IDataTemplate template)
{
var valid = template switch
{
ITypedDataTemplate typed => typed.DataType is not null,
_ => true
};
if (!valid)
{
throw new InvalidOperationException("DataTemplate inside of DataTemplates must have a DataType set. Set DataType property or use ItemTemplate with single template instead.");
}
} }
} }
} }

10
src/Avalonia.Controls/Templates/ITypedDataTemplate.cs

@ -0,0 +1,10 @@
using System;
using Avalonia.Metadata;
namespace Avalonia.Controls.Templates;
public interface ITypedDataTemplate : IDataTemplate
{
[DataType]
Type? DataType { get; }
}

4
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs

@ -35,7 +35,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer()); Transformers.Insert(2, _designTransformer = new AvaloniaXamlIlDesignPropertiesTransformer());
Transformers.Insert(3, _bindingTransformer = new AvaloniaBindingExtensionTransformer()); Transformers.Insert(3, _bindingTransformer = new AvaloniaBindingExtensionTransformer());
// Targeted // Targeted
InsertBefore<PropertyReferenceResolver>( InsertBefore<PropertyReferenceResolver>(
new AvaloniaXamlIlResolveClassesPropertiesTransformer(), new AvaloniaXamlIlResolveClassesPropertiesTransformer(),
@ -57,6 +56,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer() new AvaloniaXamlIlResolveByNameMarkupExtensionReplacer()
); );
InsertAfter<TypeReferenceResolver>(
new XDataTypeTransformer());
// After everything else // After everything else
InsertBefore<NewObjectTransformer>( InsertBefore<NewObjectTransformer>(
new AddNameScopeRegistration(), new AddNameScopeRegistration(),

73
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/XDataTypeTransformer.cs

@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.Linq;
using XamlX;
using XamlX.Ast;
using XamlX.Transform;
using XamlX.Transform.Transformers;
using XamlX.TypeSystem;
namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
internal class XDataTypeTransformer : IXamlAstTransformer
{
private const string DataTypePropertyName = "DataType";
/// <summary>
/// Converts x:DataType directives to regular DataType assignments if property with Avalonia.Metadata.DataTypeAttribute exists.
/// </summary>
/// <returns></returns>
public IXamlAstNode Transform(AstTransformationContext context, IXamlAstNode node)
{
if (node is XamlAstObjectNode on)
{
for (var c = 0; c < on.Children.Count; c++)
{
var ch = on.Children[c];
if (ch is XamlAstXmlDirective { Namespace: XamlNamespaces.Xaml2006, Name: DataTypePropertyName } d)
{
if (on.Children.OfType<XamlAstXamlPropertyValueNode>()
.Any(p => ((XamlAstNamePropertyReference)p.Property)?.Name == DataTypePropertyName))
{
// Break iteration if any DataType property was already set by user code.
break;
}
var templateDataTypeAttribute = context.GetAvaloniaTypes().DataTypeAttribute;
var clrType = (on.Type as XamlAstClrTypeReference)?.Type;
if (clrType is null)
{
break;
}
// Technically it's possible to map "x:DataType" to a property with [DataType] attribute regardless of its name,
// but we go explicitly strict here and check the name as well.
var (declaringType, dataTypeProperty) = GetAllProperties(clrType)
.FirstOrDefault(t => t.property.Name == DataTypePropertyName && t.property.CustomAttributes
.Any(a => a.Type == templateDataTypeAttribute));
if (dataTypeProperty is not null)
{
on.Children[c] = new XamlAstXamlPropertyValueNode(d,
new XamlAstNamePropertyReference(d,
new XamlAstClrTypeReference(ch, declaringType, false), dataTypeProperty.Name,
on.Type),
d.Values);
}
}
}
}
return node;
}
private static IEnumerable<(IXamlType declaringType, IXamlProperty property)> GetAllProperties(IXamlType t)
{
foreach (var p in t.Properties)
yield return (t, p);
if(t.BaseType!=null)
foreach (var tuple in GetAllProperties(t.BaseType))
yield return tuple;
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs

@ -5,7 +5,7 @@ using Avalonia.Metadata;
namespace Avalonia.Markup.Xaml.Templates namespace Avalonia.Markup.Xaml.Templates
{ {
public class DataTemplate : IRecyclingDataTemplate public class DataTemplate : IRecyclingDataTemplate, ITypedDataTemplate
{ {
[DataType] [DataType]
public Type DataType { get; set; } public Type DataType { get; set; }

2
src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs

@ -9,7 +9,7 @@ using Avalonia.Metadata;
namespace Avalonia.Markup.Xaml.Templates namespace Avalonia.Markup.Xaml.Templates
{ {
public class TreeDataTemplate : ITreeDataTemplate public class TreeDataTemplate : ITreeDataTemplate, ITypedDataTemplate
{ {
[DataType] [DataType]
public Type DataType { get; set; } public Type DataType { get; set; }

7
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -17,6 +17,7 @@ using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using JetBrains.Annotations;
using XamlX; using XamlX;
using Xunit; using Xunit;
@ -413,11 +414,11 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests' xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
x:DataType='local:TestDataContext'> x:DataType='local:TestDataContext'>
<ItemsControl Items='{CompiledBinding ListProperty}' Name='target'> <ItemsControl Items='{CompiledBinding ListProperty}' Name='target'>
<ItemsControl.DataTemplates> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text='{CompiledBinding}' Name='textBlock' /> <TextBlock Text='{CompiledBinding}' Name='textBlock' />
</DataTemplate> </DataTemplate>
</ItemsControl.DataTemplates> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>
</Window>"; </Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml); var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
@ -1527,7 +1528,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
[TemplateContent] [TemplateContent]
public object Content { get; set; } public object Content { get; set; }
public bool Match(object data) => FancyDataType.IsInstanceOfType(data); public bool Match(object data) => FancyDataType?.IsInstanceOfType(data) ?? true;
public IControl Build(object data) => TemplateContent.Load(Content)?.Control; public IControl Build(object data) => TemplateContent.Load(Content)?.Control;
} }

8
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs

@ -74,18 +74,18 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
<Window xmlns='https://github.com/avaloniaui'> <Window xmlns='https://github.com/avaloniaui'>
<DockPanel> <DockPanel>
<TabStrip Name='strip' DockPanel.Dock='Top' Items='{Binding Items}' SelectedIndex='0'> <TabStrip Name='strip' DockPanel.Dock='Top' Items='{Binding Items}' SelectedIndex='0'>
<TabStrip.DataTemplates> <TabStrip.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text='{Binding Header}'/> <TextBlock Text='{Binding Header}'/>
</DataTemplate> </DataTemplate>
</TabStrip.DataTemplates> </TabStrip.ItemTemplate>
</TabStrip> </TabStrip>
<Carousel Name='carousel' Items='{Binding Items}' SelectedIndex='{Binding #strip.SelectedIndex}'> <Carousel Name='carousel' Items='{Binding Items}' SelectedIndex='{Binding #strip.SelectedIndex}'>
<Carousel.DataTemplates> <Carousel.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text='{Binding Detail}'/> <TextBlock Text='{Binding Detail}'/>
</DataTemplate> </DataTemplate>
</Carousel.DataTemplates> </Carousel.ItemTemplate>
</Carousel> </Carousel>
</DockPanel> </DockPanel>
</Window>"; </Window>";

113
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/DataTemplateTests.cs

@ -1,5 +1,11 @@
using System;
using System.Linq;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Presenters; using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;
using Avalonia.Metadata;
using Avalonia.UnitTests; using Avalonia.UnitTests;
using Xunit; using Xunit;
@ -89,6 +95,93 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
} }
} }
[Fact]
public void XDataType_Should_Be_Assigned_To_Clr_Property()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:sys='clr-namespace:System;assembly=netstandard'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.DataTemplates>
<DataTemplate x:DataType='sys:String'>
<Canvas Name='foo'/>
</DataTemplate>
</Window.DataTemplates>
<ContentControl Name='target' Content='Foo'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
var template = (DataTemplate)window.DataTemplates.First();
window.ApplyTemplate();
target.ApplyTemplate();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.Equal(typeof(string), template.DataType);
Assert.IsType<Canvas>(target.Presenter.Child);
}
}
[Fact]
public void XDataType_Should_Be_Ignored_If_DataType_Already_Set()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:sys='clr-namespace:System;assembly=netstandard'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.DataTemplates>
<DataTemplate DataType='sys:String' x:DataType='UserControl'>
<Canvas Name='foo'/>
</DataTemplate>
</Window.DataTemplates>
<ContentControl Name='target' Content='Foo'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
window.ApplyTemplate();
target.ApplyTemplate();
((ContentPresenter)target.Presenter).UpdateChild();
Assert.IsType<Canvas>(target.Presenter.Child);
}
}
[Fact]
public void XDataType_Should_Be_Ignored_If_DataType_Has_Non_Standard_Name()
{
// We don't want DataType to be mapped to FancyDataType, avoid possible confusion.
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:sys='clr-namespace:System;assembly=netstandard'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
<ContentControl Name='target' Content='Foo'>
<ContentControl.ContentTemplate>
<local:CustomDataTemplate x:DataType='local:TestDataContext'>
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
</local:CustomDataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.FindControl<ContentControl>("target");
window.ApplyTemplate();
target.ApplyTemplate();
((ContentPresenter)target.Presenter).UpdateChild();
var dataTemplate = (CustomDataTemplate)target.ContentTemplate;
Assert.Null(dataTemplate.FancyDataType);
}
}
[Fact] [Fact]
public void Can_Set_DataContext_In_DataTemplate() public void Can_Set_DataContext_In_DataTemplate()
{ {
@ -132,5 +225,25 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.Same(viewModel.Child.Child, canvas.DataContext); Assert.Same(viewModel.Child.Child, canvas.DataContext);
} }
} }
[Fact]
public void DataTemplates_Without_Type_Should_Throw()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:sys='clr-namespace:System;assembly=netstandard'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.DataTemplates>
<DataTemplate>
<Canvas Name='foo'/>
</DataTemplate>
</Window.DataTemplates>
<ContentControl Name='target' Content='Foo'/>
</Window>";
Assert.Throws<InvalidOperationException>(() => (Window)AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
} }
} }

19
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/TreeDataTemplateTests.cs

@ -14,12 +14,29 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
{ {
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper)) using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
{ {
var xaml = "<DataTemplates xmlns='https://github.com/avaloniaui'><TreeDataTemplate ItemsSource='{Binding}'/></DataTemplates>"; var xaml = "<DataTemplates xmlns='https://github.com/avaloniaui'><TreeDataTemplate DataType='Control' ItemsSource='{Binding}'/></DataTemplates>";
var templates = (DataTemplates)AvaloniaRuntimeXamlLoader.Load(xaml); var templates = (DataTemplates)AvaloniaRuntimeXamlLoader.Load(xaml);
var template = (TreeDataTemplate)(templates.First()); var template = (TreeDataTemplate)(templates.First());
Assert.IsType<Binding>(template.ItemsSource); Assert.IsType<Binding>(template.ItemsSource);
} }
} }
[Fact]
public void XDataType_Should_Be_Assigned_To_Clr_Property()
{
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
{
var xaml = @"
<DataTemplates xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<TreeDataTemplate x:DataType='x:String' />
</DataTemplates>";
var templates = (DataTemplates)AvaloniaRuntimeXamlLoader.Load(xaml);
var template = (TreeDataTemplate)(templates.First());
Assert.Equal(typeof(string), template.DataType);
}
}
} }
} }

Loading…
Cancel
Save