Browse Source

Merge branch 'master' into alloc-scene-hittest

pull/3315/head
Dariusz Komosiński 7 years ago
committed by GitHub
parent
commit
65fa7e00ea
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      native/Avalonia.Native/src/OSX/gl.mm
  2. 2
      native/Avalonia.Native/src/OSX/window.h
  3. 89
      native/Avalonia.Native/src/OSX/window.mm
  4. 2
      src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
  5. 3
      src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs
  6. 18
      src/Avalonia.Input/FocusManager.cs
  7. 5
      src/Avalonia.Native/WindowImplBase.cs
  8. 2
      src/Avalonia.Visuals/Matrix.cs
  9. 19
      src/Avalonia.Visuals/Media/Transform.cs
  10. 2
      src/Avalonia.Visuals/Point.cs
  11. 11
      src/Avalonia.Visuals/RelativePoint.cs
  12. 21
      src/Avalonia.Visuals/Vector.cs
  13. 3
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  14. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs
  15. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github
  16. 31
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs
  17. 23
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  18. 52
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

24
native/Avalonia.Native/src/OSX/gl.mm

@ -1,6 +1,7 @@
#include "common.h" #include "common.h"
#include <OpenGL/gl.h> #include <OpenGL/gl.h>
#include <dlfcn.h> #include <dlfcn.h>
#include "window.h"
template <typename T, size_t N> char (&ArrayCounter(T (&a)[N]))[N]; template <typename T, size_t N> char (&ArrayCounter(T (&a)[N]))[N];
#define ARRAY_COUNT(a) (sizeof(ArrayCounter(a))) #define ARRAY_COUNT(a) (sizeof(ArrayCounter(a)))
@ -181,12 +182,12 @@ extern IAvnGlFeature* GetGlFeature()
class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession> class AvnGlRenderingSession : public ComSingleObject<IAvnGlSurfaceRenderingSession, &IID_IAvnGlSurfaceRenderingSession>
{ {
NSView* _view; AvnView* _view;
NSWindow* _window; AvnWindow* _window;
NSOpenGLContext* _context; NSOpenGLContext* _context;
public: public:
FORWARD_IUNKNOWN() FORWARD_IUNKNOWN()
AvnGlRenderingSession(NSWindow*window, NSView* view, NSOpenGLContext* context) AvnGlRenderingSession(AvnWindow*window, AvnView* view, NSOpenGLContext* context)
{ {
_context = context; _context = context;
_window = window; _window = window;
@ -195,14 +196,12 @@ public:
virtual HRESULT GetPixelSize(AvnPixelSize* ret) override virtual HRESULT GetPixelSize(AvnPixelSize* ret) override
{ {
auto fsize = [_view convertSizeToBacking: [_view frame].size]; *ret = [_view getPixelSize];
ret->Width = (int)fsize.width;
ret->Height = (int)fsize.height;
return S_OK; return S_OK;
} }
virtual HRESULT GetScaling(double* ret) override virtual HRESULT GetScaling(double* ret) override
{ {
*ret = [_window backingScaleFactor]; *ret = [_window getScaling];
return S_OK; return S_OK;
} }
@ -234,8 +233,17 @@ public:
auto f = GetFeature(); auto f = GetFeature();
if(f == NULL) if(f == NULL)
return E_FAIL; return E_FAIL;
if(![_view lockFocusIfCanDraw])
@try
{
if(![_view lockFocusIfCanDraw])
return E_ABORT;
}
@catch(NSException* exception)
{
return E_ABORT; return E_ABORT;
}
auto gl = _context; auto gl = _context;
CGLLockContext([_context CGLContextObj]); CGLLockContext([_context CGLContextObj]);

2
native/Avalonia.Native/src/OSX/window.h

@ -12,6 +12,7 @@ class WindowBaseImpl;
-(AvnPoint) translateLocalPoint:(AvnPoint)pt; -(AvnPoint) translateLocalPoint:(AvnPoint)pt;
-(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose; -(void) setSwRenderedFrame: (AvnFramebuffer* _Nonnull) fb dispose: (IUnknown* _Nonnull) dispose;
-(void) onClosed; -(void) onClosed;
-(AvnPixelSize) getPixelSize;
@end @end
@interface AvnWindow : NSWindow <NSWindowDelegate> @interface AvnWindow : NSWindow <NSWindowDelegate>
@ -22,6 +23,7 @@ class WindowBaseImpl;
-(void) restoreParentWindow; -(void) restoreParentWindow;
-(bool) shouldTryToHandleEvents; -(bool) shouldTryToHandleEvents;
-(void) applyMenu:(NSMenu *)menu; -(void) applyMenu:(NSMenu *)menu;
-(double) getScaling;
@end @end
struct INSWindowHolder struct INSWindowHolder

89
native/Avalonia.Native/src/OSX/window.mm

@ -195,7 +195,11 @@ public:
{ {
@autoreleasepool @autoreleasepool
{ {
[Window close]; if (Window != nullptr)
{
[Window close];
}
return S_OK; return S_OK;
} }
} }
@ -291,7 +295,14 @@ public:
{ {
@autoreleasepool @autoreleasepool
{ {
return [View lockFocusIfCanDraw] == YES; @try
{
return [View lockFocusIfCanDraw] == YES;
}
@catch (NSException*)
{
return NO;
}
} }
} }
@ -719,15 +730,33 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed, _isMouseOver; bool _isLeftPressed, _isMiddlePressed, _isRightPressed, _isXButton1Pressed, _isXButton2Pressed, _isMouseOver;
NSEvent* _lastMouseDownEvent; NSEvent* _lastMouseDownEvent;
bool _lastKeyHandled; bool _lastKeyHandled;
AvnPixelSize _lastPixelSize;
} }
- (void)dealloc - (void)onClosed
{ {
@synchronized (self)
{
_parent = nullptr;
}
} }
- (void)onClosed - (BOOL)lockFocusIfCanDraw
{
@synchronized (self)
{
if(_parent == nullptr)
{
return NO;
}
}
return [super lockFocusIfCanDraw];
}
-(AvnPixelSize) getPixelSize
{ {
_parent = NULL; return _lastPixelSize;
} }
- (NSEvent*) lastMouseDownEvent - (NSEvent*) lastMouseDownEvent
@ -742,6 +771,8 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self setWantsLayer:YES]; [self setWantsLayer:YES];
_parent = parent; _parent = parent;
_area = nullptr; _area = nullptr;
_lastPixelSize.Height = 100;
_lastPixelSize.Width = 100;
return self; return self;
} }
@ -783,6 +814,10 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self addTrackingArea:_area]; [self addTrackingArea:_area];
_parent->UpdateCursor(); _parent->UpdateCursor();
auto fsize = [self convertSizeToBacking: [self frame].size];
_lastPixelSize.Width = (int)fsize.width;
_lastPixelSize.Height = (int)fsize.height;
_parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height}); _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
} }
@ -812,7 +847,13 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (void)drawRect:(NSRect)dirtyRect - (void)drawRect:(NSRect)dirtyRect
{ {
if (_parent == nullptr)
{
return;
}
_parent->BaseEvents->RunRenderPriorityJobs(); _parent->BaseEvents->RunRenderPriorityJobs();
@synchronized (self) { @synchronized (self) {
if(_swRenderedFrame != NULL) if(_swRenderedFrame != NULL)
{ {
@ -879,7 +920,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
- (void) viewDidChangeBackingProperties - (void) viewDidChangeBackingProperties
{ {
auto fsize = [self convertSizeToBacking: [self frame].size];
_lastPixelSize.Width = (int)fsize.width;
_lastPixelSize.Height = (int)fsize.height;
_parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]); _parent->BaseEvents->ScalingChanged([_parent->Window backingScaleFactor]);
[super viewDidChangeBackingProperties]; [super viewDidChangeBackingProperties];
} }
@ -1161,6 +1207,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
bool _closed; bool _closed;
NSMenu* _menu; NSMenu* _menu;
bool _isAppMenuApplied; bool _isAppMenuApplied;
double _lastScaling;
}
-(double) getScaling
{
return _lastScaling;
} }
+(void)closeAll +(void)closeAll
@ -1174,10 +1226,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
} }
} }
- (void)dealloc
{
}
- (void)pollModalSession:(nonnull NSModalSession)session - (void)pollModalSession:(nonnull NSModalSession)session
{ {
auto response = [NSApp runModalSession:session]; auto response = [NSApp runModalSession:session];
@ -1232,6 +1280,9 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self setReleasedWhenClosed:false]; [self setReleasedWhenClosed:false];
_parent = parent; _parent = parent;
[self setDelegate:self]; [self setDelegate:self];
_closed = false;
_lastScaling = [self backingScaleFactor];
return self; return self;
} }
@ -1247,6 +1298,11 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
return true; return true;
} }
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
{
_lastScaling = [self backingScaleFactor];
}
- (void)windowWillClose:(NSNotification *)notification - (void)windowWillClose:(NSNotification *)notification
{ {
_closed = true; _closed = true;
@ -1257,9 +1313,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
[self restoreParentWindow]; [self restoreParentWindow];
parent->BaseEvents->Closed(); parent->BaseEvents->Closed();
[parent->View onClosed]; [parent->View onClosed];
dispatch_async(dispatch_get_main_queue(), ^{
[self setContentView: nil];
});
} }
} }
@ -1406,18 +1459,6 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
_parent->GetPosition(&position); _parent->GetPosition(&position);
_parent->BaseEvents->PositionChanged(position); _parent->BaseEvents->PositionChanged(position);
} }
// TODO this breaks resizing.
/*- (void)windowDidResize:(NSNotification *)notification
{
auto parent = dynamic_cast<IWindowStateChanged*>(_parent.operator->());
if(parent != nullptr)
{
parent->WindowStateChanged();
}
}*/
@end @end
class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup class PopupImpl : public virtual WindowBaseImpl, public IAvnPopup

2
src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs

@ -306,7 +306,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
if (placement == PlacementMode.Pointer) if (placement == PlacementMode.Pointer)
{ {
positionerParameters.AnchorRectangle = new Rect(pointer, new Size(1, 1)); positionerParameters.AnchorRectangle = new Rect(pointer, new Size(1, 1));
positionerParameters.Anchor = PopupPositioningEdge.BottomRight; positionerParameters.Anchor = PopupPositioningEdge.TopLeft;
positionerParameters.Gravity = PopupPositioningEdge.BottomRight; positionerParameters.Gravity = PopupPositioningEdge.BottomRight;
} }
else else

3
src/Avalonia.FreeDesktop/LinuxMountedVolumeInfoListener.cs

@ -47,7 +47,8 @@ namespace Avalonia.FreeDesktop
var fProcMounts = File.ReadAllLines(ProcMountsDir) var fProcMounts = File.ReadAllLines(ProcMountsDir)
.Select(x => x.Split(' ')) .Select(x => x.Split(' '))
.Select(x => (x[0], x[1])); .Select(x => (x[0], x[1]))
.Where(x => !x.Item2.StartsWith("/snap/", StringComparison.InvariantCultureIgnoreCase));
var labelDirEnum = Directory.Exists(DevByLabelDir) ? var labelDirEnum = Directory.Exists(DevByLabelDir) ?
new DirectoryInfo(DevByLabelDir).GetFiles() : Enumerable.Empty<FileInfo>(); new DirectoryInfo(DevByLabelDir).GetFiles() : Enumerable.Empty<FileInfo>();

18
src/Avalonia.Input/FocusManager.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.VisualTree; using Avalonia.VisualTree;
@ -17,8 +18,8 @@ namespace Avalonia.Input
/// <summary> /// <summary>
/// The focus scopes in which the focus is currently defined. /// The focus scopes in which the focus is currently defined.
/// </summary> /// </summary>
private readonly Dictionary<IFocusScope, IInputElement> _focusScopes = private readonly ConditionalWeakTable<IFocusScope, IInputElement> _focusScopes =
new Dictionary<IFocusScope, IInputElement>(); new ConditionalWeakTable<IFocusScope, IInputElement>();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="FocusManager"/> class. /// Initializes a new instance of the <see cref="FocusManager"/> class.
@ -110,7 +111,18 @@ namespace Avalonia.Input
{ {
Contract.Requires<ArgumentNullException>(scope != null); Contract.Requires<ArgumentNullException>(scope != null);
_focusScopes[scope] = element; if (_focusScopes.TryGetValue(scope, out IInputElement existingElement))
{
if (element != existingElement)
{
_focusScopes.Remove(scope);
_focusScopes.Add(scope, element);
}
}
else
{
_focusScopes.Add(scope, element);
}
if (Scope == scope) if (Scope == scope)
{ {

5
src/Avalonia.Native/WindowImplBase.cs

@ -353,6 +353,11 @@ namespace Avalonia.Native
public void SetCursor(IPlatformHandle cursor) public void SetCursor(IPlatformHandle cursor)
{ {
if (_native == null)
{
return;
}
var newCursor = cursor as AvaloniaNativeCursor; var newCursor = cursor as AvaloniaNativeCursor;
newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor); newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor);
_native.Cursor = newCursor.Cursor; _native.Cursor = newCursor.Cursor;

2
src/Avalonia.Visuals/Matrix.cs

@ -306,7 +306,7 @@ namespace Avalonia
/// <summary> /// <summary>
/// Parses a <see cref="Matrix"/> string. /// Parses a <see cref="Matrix"/> string.
/// </summary> /// </summary>
/// <param name="s">The string.</param> /// <param name="s">Six comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY) that describe the new <see cref="Matrix"/></param>
/// <returns>The <see cref="Matrix"/>.</returns> /// <returns>The <see cref="Matrix"/>.</returns>
public static Matrix Parse(string s) public static Matrix Parse(string s)
{ {

19
src/Avalonia.Visuals/Media/Transform.cs

@ -28,6 +28,16 @@ namespace Avalonia.Media
/// </summary> /// </summary>
public abstract Matrix Value { get; } public abstract Matrix Value { get; }
/// <summary>
/// Parses a <see cref="Transform"/> string.
/// </summary>
/// <param name="s">Six comma-delimited double values that describe the new <see cref="Transform"/>. For details check <see cref="Matrix.Parse(string)"/> </param>
/// <returns>The <see cref="Transform"/>.</returns>
public static Transform Parse(string s)
{
return new MatrixTransform(Matrix.Parse(s));
}
/// <summary> /// <summary>
/// Raises the <see cref="Changed"/> event. /// Raises the <see cref="Changed"/> event.
/// </summary> /// </summary>
@ -35,5 +45,14 @@ namespace Avalonia.Media
{ {
Changed?.Invoke(this, EventArgs.Empty); Changed?.Invoke(this, EventArgs.Empty);
} }
/// <summary>
/// Returns a String representing this transform matrix instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
return Value.ToString();
}
} }
} }

2
src/Avalonia.Visuals/Point.cs

@ -175,7 +175,7 @@ namespace Avalonia
/// Parses a <see cref="Point"/> string. /// Parses a <see cref="Point"/> string.
/// </summary> /// </summary>
/// <param name="s">The string.</param> /// <param name="s">The string.</param>
/// <returns>The <see cref="Thickness"/>.</returns> /// <returns>The <see cref="Point"/>.</returns>
public static Point Parse(string s) public static Point Parse(string s)
{ {
using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point.")) using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Point."))

11
src/Avalonia.Visuals/RelativePoint.cs

@ -177,5 +177,16 @@ namespace Avalonia
unit); unit);
} }
} }
/// <summary>
/// Returns a String representing this RelativePoint instance.
/// </summary>
/// <returns>The string representation.</returns>
public override string ToString()
{
return _unit == RelativeUnit.Absolute ?
_point.ToString() :
string.Format(CultureInfo.InvariantCulture, "{0}%, {1}%", _point.X * 100, _point.Y * 100);
}
} }
} }

21
src/Avalonia.Visuals/Vector.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using Avalonia.Animation.Animators; using Avalonia.Animation.Animators;
using Avalonia.Utilities;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Avalonia namespace Avalonia
@ -85,6 +86,22 @@ namespace Avalonia
public static Vector operator /(Vector vector, double scale) public static Vector operator /(Vector vector, double scale)
=> Divide(vector, scale); => Divide(vector, scale);
/// <summary>
/// Parses a <see cref="Vector"/> string.
/// </summary>
/// <param name="s">The string.</param>
/// <returns>The <see cref="Vector"/>.</returns>
public static Vector Parse(string s)
{
using (var tokenizer = new StringTokenizer(s, CultureInfo.InvariantCulture, exceptionMessage: "Invalid Vector."))
{
return new Vector(
tokenizer.ReadDouble(),
tokenizer.ReadDouble()
);
}
}
/// <summary> /// <summary>
/// Length of the vector /// Length of the vector
/// </summary> /// </summary>
@ -166,9 +183,9 @@ namespace Avalonia
} }
/// <summary> /// <summary>
/// Returns the string representation of the point. /// Returns the string representation of the vector.
/// </summary> /// </summary>
/// <returns>The string representation of the point.</returns> /// <returns>The string representation of the vector.</returns>
public override string ToString() public override string ToString()
{ {
return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y); return string.Format(CultureInfo.InvariantCulture, "{0}, {1}", _x, _y);

3
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@ -41,6 +41,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
StringFormat = StringFormat, StringFormat = StringFormat,
RelativeSource = RelativeSource, RelativeSource = RelativeSource,
DefaultAnchor = new WeakReference(GetDefaultAnchor(descriptorContext)), DefaultAnchor = new WeakReference(GetDefaultAnchor(descriptorContext)),
TargetNullValue = TargetNullValue,
NameScope = new WeakReference<INameScope>(serviceProvider.GetService<INameScope>()) NameScope = new WeakReference<INameScope>(serviceProvider.GetService<INameScope>())
}; };
} }
@ -86,5 +87,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
public string StringFormat { get; set; } public string StringFormat { get; set; }
public RelativeSource RelativeSource { get; set; } public RelativeSource RelativeSource { get; set; }
public object TargetNullValue { get; set; }
} }
} }

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlControlTemplateTargetTypeMetadataTransformer.cs

@ -25,7 +25,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
if ((tt?.Values.FirstOrDefault() is XamlIlTypeExtensionNode tn)) if ((tt?.Values.FirstOrDefault() is XamlIlTypeExtensionNode tn))
{ {
targetType = tn.Type; targetType = tn.Value;
} }
else else
{ {

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/xamlil.github

@ -1 +1 @@
Subproject commit ad9915e19398a49c5a11b66000c361659ca692b3 Subproject commit 4c4b6cf8ff0894c925d87b27d4fc7a064440c218

31
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/BindingExtensionTests.cs

@ -38,6 +38,37 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
Assert.Equal("foobar", textBlock.Text); Assert.Equal("foobar", textBlock.Text);
} }
} }
[Fact]
public void BindingExtension_Binds_To_TargetNullValue()
{
using (StyledWindow())
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Window.Resources>
<x:String x:Key='text'>foobar</x:String>
</Window.Resources>
<TextBlock Name='textBlock' Text='{Binding Foo, TargetNullValue={StaticResource text}}'/>
</Window>";
var loader = new AvaloniaXamlLoader();
var window = (Window)loader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
window.DataContext = new FooBar();
window.Show();
Assert.Equal("foobar", textBlock.Text);
}
}
private class FooBar
{
public object Foo { get; } = null;
}
private IDisposable StyledWindow(params (string, string)[] assets) private IDisposable StyledWindow(params (string, string)[] assets)
{ {

23
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@ -307,6 +307,23 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.Equal("child", child.Name); Assert.Equal("child", child.Name);
} }
[Fact]
public void ControlTemplate_With_TargetType_Is_Operational()
{
var xaml = @"
<ControlTemplate xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
TargetType='{x:Type ContentControl}'>
<ContentPresenter Content='{TemplateBinding Content}' />
</ControlTemplate>
";
var template = AvaloniaXamlLoader.Parse<ControlTemplate>(xaml);
Assert.Equal(typeof(ContentControl), template.TargetType);
Assert.IsType(typeof(ContentPresenter), template.Build(new ContentControl()).Control);
}
[Fact] [Fact]
public void ControlTemplate_With_Panel_Children_Are_Added() public void ControlTemplate_With_Panel_Children_Are_Added()
{ {
@ -704,11 +721,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
} }
} }
[Fact]
[Fact(Skip =
@"Doesn't work with Portable.xaml, it's working in different creation order -
Handled in test 'Control_Is_Added_To_Parent_Before_Final_EndInit'
do we need it?")]
public void Control_Is_Added_To_Parent_Before_Properties_Are_Set() public void Control_Is_Added_To_Parent_Before_Properties_Are_Set()
{ {
using (UnitTestApplication.Start(TestServices.StyledWindow)) using (UnitTestApplication.Start(TestServices.StyledWindow))

52
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

@ -5,6 +5,7 @@ using System.Xml;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Data; using Avalonia.Markup.Data;
using Avalonia.Markup.Xaml.Styling; using Avalonia.Markup.Xaml.Styling;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Styling; using Avalonia.Styling;
using Avalonia.UnitTests; using Avalonia.UnitTests;
@ -38,6 +39,57 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
} }
} }
[Fact]
public void DataTemplate_Can_Be_Added_To_Style_Resources()
{
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
{
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<UserControl.Styles>
<Style>
<Style.Resources>
<DataTemplate x:Key='dataTemplate'><TextBlock/></DataTemplate>
</Style.Resources>
</Style>
</UserControl.Styles>
</UserControl>";
var loader = new AvaloniaXamlLoader();
var userControl = (UserControl)loader.Load(xaml);
var dataTemplate = (DataTemplate)((Style)userControl.Styles[0]).Resources["dataTemplate"];
Assert.NotNull(dataTemplate);
}
}
[Fact]
public void ControlTemplate_Can_Be_Added_To_Style_Resources()
{
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
{
var xaml = @"
<UserControl xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<UserControl.Styles>
<Style>
<Style.Resources>
<ControlTemplate x:Key='controlTemplate' TargetType='{x:Type Button}'>
<ContentPresenter Content='{TemplateBinding Content}'/>
</ControlTemplate>
</Style.Resources>
</Style>
</UserControl.Styles>
</UserControl>";
var loader = new AvaloniaXamlLoader();
var userControl = (UserControl)loader.Load(xaml);
var controlTemplate = (ControlTemplate)((Style)userControl.Styles[0]).Resources["controlTemplate"];
Assert.NotNull(controlTemplate);
Assert.Equal(typeof(Button), controlTemplate.TargetType);
}
}
[Fact] [Fact]
public void SolidColorBrush_Can_Be_Added_To_Style_Resources() public void SolidColorBrush_Can_Be_Added_To_Style_Resources()
{ {

Loading…
Cancel
Save