diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000..c5a719ce90
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+open_collective: avalonia
diff --git a/.gitignore b/.gitignore
index 2b2c9c3d0d..971c945246 100644
--- a/.gitignore
+++ b/.gitignore
@@ -196,3 +196,5 @@ ModuleCache.noindex/
Build/Intermediates.noindex/
info.plist
build-intermediate
+obj-Direct2D1/
+obj-Skia/
diff --git a/.gitmodules b/.gitmodules
index 22a241f120..10c780c09f 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,3 @@
-[submodule "src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github"]
- path = src/Markup/Avalonia.Markup.Xaml/PortableXaml/portable.xaml.github
- url = https://github.com/AvaloniaUI/Portable.Xaml.git
[submodule "nukebuild/Numerge"]
path = nukebuild/Numerge
url = https://github.com/kekekeks/Numerge.git
diff --git a/Avalonia.sln b/Avalonia.sln
index 484d7a4cde..f86c18ba1e 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -146,7 +146,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\Serilog.props = build\Serilog.props
build\SharpDX.props = build\SharpDX.props
build\SkiaSharp.props = build\SkiaSharp.props
- build\Splat.props = build\Splat.props
build\System.Memory.props = build\System.Memory.props
build\XUnit.props = build\XUnit.props
EndProjectSection
diff --git a/dirs.proj b/dirs.proj
index 4939a158bb..e56320e73f 100644
--- a/dirs.proj
+++ b/dirs.proj
@@ -8,10 +8,11 @@
-
-
+
+
+
diff --git a/native/Avalonia.Native/inc/avalonia-native.h b/native/Avalonia.Native/inc/avalonia-native.h
index 4b814a9cfb..a35f4f3eeb 100644
--- a/native/Avalonia.Native/inc/avalonia-native.h
+++ b/native/Avalonia.Native/inc/avalonia-native.h
@@ -144,6 +144,7 @@ enum AvnStandardCursorType
CursorDragMove,
CursorDragCopy,
CursorDragLink,
+ CursorNone
};
enum AvnWindowEdge
diff --git a/native/Avalonia.Native/src/OSX/cursor.h b/native/Avalonia.Native/src/OSX/cursor.h
index a8eb49c0b9..cfe91955d8 100644
--- a/native/Avalonia.Native/src/OSX/cursor.h
+++ b/native/Avalonia.Native/src/OSX/cursor.h
@@ -11,18 +11,24 @@ class Cursor : public ComSingleObject
{
private:
NSCursor * _native;
-
+ bool _isHidden;
public:
FORWARD_IUNKNOWN()
- Cursor(NSCursor * cursor)
+ Cursor(NSCursor * cursor, bool isHidden = false)
{
_native = cursor;
+ _isHidden = isHidden;
}
NSCursor* GetNative()
{
return _native;
}
+
+ bool IsHidden ()
+ {
+ return _isHidden;
+ }
};
extern std::map s_cursorMap;
diff --git a/native/Avalonia.Native/src/OSX/cursor.mm b/native/Avalonia.Native/src/OSX/cursor.mm
index bd2c94a4d8..799fa9e8e6 100644
--- a/native/Avalonia.Native/src/OSX/cursor.mm
+++ b/native/Avalonia.Native/src/OSX/cursor.mm
@@ -21,6 +21,7 @@ class CursorFactory : public ComSingleObject s_cursorMap =
{
@@ -46,11 +47,13 @@ class CursorFactory : public ComSingleObject(cursor);
this->cursor = avnCursor->GetNative();
UpdateCursor();
+
+ if(avnCursor->IsHidden())
+ {
+ [NSCursor hide];
+ }
+ else
+ {
+ [NSCursor unhide];
+ }
+
return S_OK;
}
}
diff --git a/packages/Avalonia/Avalonia.csproj b/packages/Avalonia/Avalonia.csproj
index 489cb228aa..2c5a09bee7 100644
--- a/packages/Avalonia/Avalonia.csproj
+++ b/packages/Avalonia/Avalonia.csproj
@@ -1,6 +1,7 @@
netstandard2.0;net461;netcoreapp2.0
+ Avalonia
diff --git a/readme.md b/readme.md
index 12f683bd55..cf995f10fb 100644
--- a/readme.md
+++ b/readme.md
@@ -8,9 +8,9 @@
## About
-Avalonia is a WPF-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of OSs: Windows (.NET Framework, .NET Core), Linux (GTK), MacOS, Android and iOS.
+Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of OSs: Windows (.NET Framework, .NET Core), Linux (libX11), MacOS, Android (experimental) and iOS (exprerimental).
-**Avalonia is currently in beta** which means that the framework is generally usable for writing applications, but there may be some bugs and breaking changes as we continue development.
+**Avalonia is currently in beta** which means that the framework is generally usable for writing applications, but there may be some bugs and breaking changes as we continue development, for more details about the status see https://github.com/AvaloniaUI/Avalonia/issues/2239
| Control catalog | Desktop platforms | Mobile platforms |
|---|---|---|
diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
index 804ca1f9b8..6a40f7187d 100644
--- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
+++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
@@ -11,6 +11,7 @@
+
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
index 93f5611ec4..4027c5cd63 100644
--- a/samples/ControlCatalog.NetCore/Program.cs
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -46,6 +46,12 @@ namespace ControlCatalog.NetCore
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
.UsePlatformDetect()
+ .With(new X11PlatformOptions {EnableMultiTouch = true})
+ .With(new Win32PlatformOptions
+ {
+ EnableMultitouch = true,
+ AllowEglInitialization = true
+ })
.UseSkia()
.UseReactiveUI();
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 9f1899acc5..1cddb9d295 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -31,6 +31,7 @@
+
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml
index 268b06f756..d1742c12b7 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml
@@ -11,7 +11,7 @@
-
+
DataGrid
A control for displaying and interacting with a data source.
@@ -52,4 +52,4 @@
-
\ No newline at end of file
+
diff --git a/samples/ControlCatalog/Pages/PointersPage.cs b/samples/ControlCatalog/Pages/PointersPage.cs
new file mode 100644
index 0000000000..a1359519e6
--- /dev/null
+++ b/samples/ControlCatalog/Pages/PointersPage.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Media;
+using Avalonia.Media.Immutable;
+
+namespace ControlCatalog.Pages
+{
+ public class PointersPage : Control
+ {
+ class PointerInfo
+ {
+ public Point Point { get; set; }
+ public Color Color { get; set; }
+ }
+
+ private static Color[] AllColors = new[]
+ {
+ Colors.Aqua,
+ Colors.Beige,
+ Colors.Chartreuse,
+ Colors.Coral,
+ Colors.Fuchsia,
+ Colors.Crimson,
+ Colors.Lavender,
+ Colors.Orange,
+ Colors.Orchid,
+ Colors.ForestGreen,
+ Colors.SteelBlue,
+ Colors.PapayaWhip,
+ Colors.PaleVioletRed,
+ Colors.Goldenrod,
+ Colors.Maroon,
+ Colors.Moccasin,
+ Colors.Navy,
+ Colors.Wheat,
+ Colors.Violet,
+ Colors.Sienna,
+ Colors.Indigo,
+ Colors.Honeydew
+ };
+
+ private Dictionary _pointers = new Dictionary();
+
+ public PointersPage()
+ {
+ ClipToBounds = true;
+ }
+
+ void UpdatePointer(PointerEventArgs e)
+ {
+ if (!_pointers.TryGetValue(e.Pointer, out var info))
+ {
+ if (e.RoutedEvent == PointerMovedEvent)
+ return;
+ var colors = AllColors.Except(_pointers.Values.Select(c => c.Color)).ToArray();
+ var color = colors[new Random().Next(0, colors.Length - 1)];
+ _pointers[e.Pointer] = info = new PointerInfo {Color = color};
+ }
+
+ info.Point = e.GetPosition(this);
+ InvalidateVisual();
+ }
+
+ protected override void OnPointerPressed(PointerPressedEventArgs e)
+ {
+ UpdatePointer(e);
+ e.Pointer.Capture(this);
+ base.OnPointerPressed(e);
+ }
+
+ protected override void OnPointerMoved(PointerEventArgs e)
+ {
+ UpdatePointer(e);
+ base.OnPointerMoved(e);
+ }
+
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
+ {
+ _pointers.Remove(e.Pointer);
+ InvalidateVisual();
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ context.FillRectangle(Brushes.Transparent, new Rect(default, Bounds.Size));
+ foreach (var pt in _pointers.Values)
+ {
+ var brush = new ImmutableSolidColorBrush(pt.Color);
+ context.DrawGeometry(brush, null, new EllipseGeometry(new Rect(pt.Point.X - 75, pt.Point.Y - 75,
+ 150, 150)));
+ }
+
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml
index 0c0a4d705b..64118a00b4 100644
--- a/samples/ControlCatalog/Pages/TextBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml
@@ -26,6 +26,10 @@
+
+
diff --git a/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs b/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
index 038f3574cc..88b1bf0b6b 100644
--- a/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Reactive;
+using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using ReactiveUI;
@@ -11,7 +12,7 @@ namespace ControlCatalog.ViewModels
public MenuPageViewModel()
{
OpenCommand = ReactiveCommand.CreateFromTask(Open);
- SaveCommand = ReactiveCommand.Create(Save);
+ SaveCommand = ReactiveCommand.Create(Save, Observable.Return(false));
OpenRecentCommand = ReactiveCommand.Create(OpenRecent);
MenuItems = new[]
diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml
index 344250ee2b..7f63e7725f 100644
--- a/samples/RenderDemo/MainWindow.xaml
+++ b/samples/RenderDemo/MainWindow.xaml
@@ -38,6 +38,9 @@
+
+
+
diff --git a/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs b/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
new file mode 100644
index 0000000000..3eb2276c48
--- /dev/null
+++ b/samples/RenderDemo/Pages/RenderTargetBitmapPage.cs
@@ -0,0 +1,49 @@
+using System.Diagnostics;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.LogicalTree;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Threading;
+using Avalonia.Visuals.Media.Imaging;
+
+namespace RenderDemo.Pages
+{
+ public class RenderTargetBitmapPage : Control
+ {
+ private RenderTargetBitmap _bitmap;
+
+ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ _bitmap = new RenderTargetBitmap(new PixelSize(200, 200), new Vector(96, 96));
+ base.OnAttachedToLogicalTree(e);
+ }
+
+ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ _bitmap.Dispose();
+ _bitmap = null;
+ base.OnDetachedFromLogicalTree(e);
+ }
+
+ readonly Stopwatch _st = Stopwatch.StartNew();
+ public override void Render(DrawingContext context)
+ {
+ using (var ctxi = _bitmap.CreateDrawingContext(null))
+ using(var ctx = new DrawingContext(ctxi, false))
+ using (ctx.PushPostTransform(Matrix.CreateTranslation(-100, -100)
+ * Matrix.CreateRotation(_st.Elapsed.TotalSeconds)
+ * Matrix.CreateTranslation(100, 100)))
+ {
+ ctxi.Clear(default);
+ ctx.FillRectangle(Brushes.Fuchsia, new Rect(50, 50, 100, 100));
+ }
+
+ context.DrawImage(_bitmap, 1,
+ new Rect(0, 0, 200, 200),
+ new Rect(0, 0, 200, 200));
+ Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
+ base.Render(context);
+ }
+ }
+}
diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
index 112925ab0f..463d499aad 100644
--- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
+++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
return null;
}
- RawMouseEventType? mouseEventType = null;
+ RawPointerEventType? mouseEventType = null;
var eventTime = DateTime.Now;
//Basic touch support
switch (e.Action)
@@ -42,17 +42,17 @@ namespace Avalonia.Android.Platform.Specific.Helpers
//may be bot flood the evnt system with too many event especially on not so powerfull mobile devices
if ((eventTime - _lastTouchMoveEventTime).TotalMilliseconds > 10)
{
- mouseEventType = RawMouseEventType.Move;
+ mouseEventType = RawPointerEventType.Move;
}
break;
case MotionEventActions.Down:
- mouseEventType = RawMouseEventType.LeftButtonDown;
+ mouseEventType = RawPointerEventType.LeftButtonDown;
break;
case MotionEventActions.Up:
- mouseEventType = RawMouseEventType.LeftButtonUp;
+ mouseEventType = RawPointerEventType.LeftButtonUp;
break;
}
@@ -75,14 +75,14 @@ namespace Avalonia.Android.Platform.Specific.Helpers
//we need to generate mouse move before first mouse down event
//as this is the way buttons are working every time
//otherwise there is a problem sometimes
- if (mouseEventType == RawMouseEventType.LeftButtonDown)
+ if (mouseEventType == RawPointerEventType.LeftButtonDown)
{
- var me = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
- RawMouseEventType.Move, _point, InputModifiers.None);
+ var me = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
+ RawPointerEventType.Move, _point, InputModifiers.None);
_view.Input(me);
}
- var mouseEvent = new RawMouseEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
+ var mouseEvent = new RawPointerEventArgs(mouseDevice, (uint)eventTime.Ticks, inputRoot,
mouseEventType.Value, _point, InputModifiers.LeftMouseButton);
_view.Input(mouseEvent);
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index dcb3ef4a2b..41b57b6e70 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -1,6 +1,9 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
+using System;
+using System.Runtime.InteropServices;
+
namespace Avalonia.Utilities
{
///
@@ -8,6 +11,89 @@ namespace Avalonia.Utilities
///
public static class MathUtilities
{
+ ///
+ /// AreClose - Returns whether or not two doubles are "close". That is, whether or
+ /// not they are within epsilon of each other.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool AreClose(double value1, double value2)
+ {
+ //in case they are Infinities (then epsilon check does not work)
+ if (value1 == value2) return true;
+ double eps = (Math.Abs(value1) + Math.Abs(value2) + 10.0) * double.Epsilon;
+ double delta = value1 - value2;
+ return (-eps < delta) && (eps > delta);
+ }
+
+ ///
+ /// LessThan - Returns whether or not the first double is less than the second double.
+ /// That is, whether or not the first is strictly less than *and* not within epsilon of
+ /// the other number.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool LessThan(double value1, double value2)
+ {
+ return (value1 < value2) && !AreClose(value1, value2);
+ }
+
+ ///
+ /// GreaterThan - Returns whether or not the first double is greater than the second double.
+ /// That is, whether or not the first is strictly greater than *and* not within epsilon of
+ /// the other number.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool GreaterThan(double value1, double value2)
+ {
+ return (value1 > value2) && !AreClose(value1, value2);
+ }
+
+ ///
+ /// LessThanOrClose - Returns whether or not the first double is less than or close to
+ /// the second double. That is, whether or not the first is strictly less than or within
+ /// epsilon of the other number.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool LessThanOrClose(double value1, double value2)
+ {
+ return (value1 < value2) || AreClose(value1, value2);
+ }
+
+ ///
+ /// GreaterThanOrClose - Returns whether or not the first double is greater than or close to
+ /// the second double. That is, whether or not the first is strictly greater than or within
+ /// epsilon of the other number.
+ ///
+ /// The first double to compare.
+ /// The second double to compare.
+ public static bool GreaterThanOrClose(double value1, double value2)
+ {
+ return (value1 > value2) || AreClose(value1, value2);
+ }
+
+ ///
+ /// IsOne - Returns whether or not the double is "close" to 1. Same as AreClose(double, 1),
+ /// but this is faster.
+ ///
+ /// The double to compare to 1.
+ public static bool IsOne(double value)
+ {
+ return Math.Abs(value - 1.0) < 10.0 * double.Epsilon;
+ }
+
+ ///
+ /// IsZero - Returns whether or not the double is "close" to 0. Same as AreClose(double, 0),
+ /// but this is faster.
+ ///
+ /// The double to compare to 0.
+ public static bool IsZero(double value)
+ {
+ return Math.Abs(value) < 10.0 * double.Epsilon;
+ }
+
///
/// Clamps a value between a minimum and maximum value.
///
@@ -31,6 +117,39 @@ namespace Avalonia.Utilities
}
}
+ ///
+ /// Calculates the value to be used for layout rounding at high DPI.
+ ///
+ /// Input value to be rounded.
+ /// Ratio of screen's DPI to layout DPI
+ /// Adjusted value that will produce layout rounding on screen at high dpi.
+ /// This is a layout helper method. It takes DPI into account and also does not return
+ /// the rounded value if it is unacceptable for layout, e.g. Infinity or NaN. It's a helper associated with
+ /// UseLayoutRounding property and should not be used as a general rounding utility.
+ public static double RoundLayoutValue(double value, double dpiScale)
+ {
+ double newValue;
+
+ // If DPI == 1, don't use DPI-aware rounding.
+ if (!MathUtilities.AreClose(dpiScale, 1.0))
+ {
+ newValue = Math.Round(value * dpiScale) / dpiScale;
+ // If rounding produces a value unacceptable to layout (NaN, Infinity or MaxValue), use the original value.
+ if (double.IsNaN(newValue) ||
+ double.IsInfinity(newValue) ||
+ MathUtilities.AreClose(newValue, double.MaxValue))
+ {
+ newValue = value;
+ }
+ }
+ else
+ {
+ newValue = Math.Round(value);
+ }
+
+ return newValue;
+ }
+
///
/// Clamps a value between a minimum and maximum value.
///
diff --git a/src/Avalonia.Build.Tasks/Program.cs b/src/Avalonia.Build.Tasks/Program.cs
index c2d0950264..d356b15408 100644
--- a/src/Avalonia.Build.Tasks/Program.cs
+++ b/src/Avalonia.Build.Tasks/Program.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.IO;
+using System.Linq;
using Microsoft.Build.Framework;
namespace Avalonia.Build.Tasks
@@ -11,8 +12,14 @@ namespace Avalonia.Build.Tasks
{
if (args.Length != 3)
{
- Console.Error.WriteLine("input references output");
- return 1;
+ if (args.Length == 1)
+ args = new[] {"original.dll", "references", "out.dll"}
+ .Select(x => Path.Combine(args[0], x)).ToArray();
+ else
+ {
+ Console.Error.WriteLine("input references output");
+ return 1;
+ }
}
return new CompileAvaloniaXamlTask()
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
index 05193172be..f94f10f792 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.Helpers.cs
@@ -4,6 +4,7 @@ using System.Linq;
using Avalonia.Utilities;
using Mono.Cecil;
using Mono.Cecil.Cil;
+using Mono.Collections.Generic;
using XamlIl.TypeSystem;
namespace Avalonia.Build.Tasks
@@ -144,6 +145,37 @@ namespace Avalonia.Build.Tasks
});
}
+
+
+ private static bool MatchThisCall(Collection instructions, int idx)
+ {
+ var i = instructions[idx];
+ // A "normal" way of passing `this` to a static method:
+
+ // ldarg.0
+ // call void [Avalonia.Markup.Xaml]Avalonia.Markup.Xaml.AvaloniaXamlLoader::Load(object)
+
+ if (i.OpCode == OpCodes.Ldarg_0 || (i.OpCode == OpCodes.Ldarg && i.Operand?.Equals(0) == true))
+ return true;
+
+ /* F# way of using `this` in constructor emits a monstrosity like this:
+ IL_01c7: ldarg.0
+ IL_01c8: ldfld class [FSharp.Core]Microsoft.FSharp.Core.FSharpRef`1 FVim.Cursor::this
+ IL_01cd: call instance !0 class [FSharp.Core]Microsoft.FSharp.Core.FSharpRef`1::get_contents()
+ IL_01d2: call !!0 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::CheckThis(!!0)
+ IL_01d7: call void [Avalonia.Markup.Xaml]Avalonia.Markup.Xaml.AvaloniaXamlLoader::Load(object)
+
+ We check for the previous call to be Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::CheckThis
+ since it actually returns `this`
+ */
+ if (i.OpCode == OpCodes.Call
+ && i.Operand is GenericInstanceMethod gim
+ && gim.Name == "CheckThis"
+ && gim.DeclaringType.FullName == "Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions")
+ return true;
+
+ return false;
+ }
}
}
diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
index ec668f2a2b..c54d8e19a1 100644
--- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
+++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
@@ -150,7 +150,8 @@ namespace Avalonia.Build.Tasks
classType = typeSystem.TargetAssembly.FindType(tn.Text);
if (classType == null)
throw new XamlIlParseException($"Unable to find type `{tn.Text}`", classDirective);
- initialRoot.Type = new XamlIlAstClrTypeReference(classDirective, classType, false);
+ compiler.OverrideRootType(parsed,
+ new XamlIlAstClrTypeReference(classDirective, classType, false));
initialRoot.Children.Remove(classDirective);
}
@@ -233,8 +234,7 @@ namespace Avalonia.Build.Tasks
var i = method.Body.Instructions;
for (var c = 1; c < i.Count; c++)
{
- if (i[c - 1].OpCode == OpCodes.Ldarg_0
- && i[c].OpCode == OpCodes.Call)
+ if (i[c].OpCode == OpCodes.Call)
{
var op = i[c].Operand as MethodReference;
@@ -253,8 +253,11 @@ namespace Avalonia.Build.Tasks
&& op.Parameters[0].ParameterType.FullName == "System.Object"
&& op.DeclaringType.FullName == "Avalonia.Markup.Xaml.AvaloniaXamlLoader")
{
- i[c].Operand = trampoline;
- foundXamlLoader = true;
+ if (MatchThisCall(i, c - 1))
+ {
+ i[c].Operand = trampoline;
+ foundXamlLoader = true;
+ }
}
}
}
diff --git a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
index 21d34ae4d6..27853a1540 100644
--- a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
+++ b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
@@ -1,6 +1,7 @@
netstandard2.0
+ Avalonia.Controls.DataGrid
diff --git a/src/Avalonia.Controls.DataGrid/DataGridRow.cs b/src/Avalonia.Controls.DataGrid/DataGridRow.cs
index 8bc76543ba..04a1575486 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridRow.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridRow.cs
@@ -881,10 +881,10 @@ namespace Avalonia.Controls
&& (double.IsNaN(_detailsContent.Height))
&& (AreDetailsVisible)
&& (!double.IsNaN(_detailsDesiredHeight))
- && !DoubleUtil.AreClose(_detailsContent.Bounds.Height, _detailsDesiredHeight)
+ && !DoubleUtil.AreClose(_detailsContent.Bounds.Inflate(_detailsContent.Margin).Height, _detailsDesiredHeight)
&& Slot != -1)
{
- _detailsDesiredHeight = _detailsContent.Bounds.Height;
+ _detailsDesiredHeight = _detailsContent.Bounds.Inflate(_detailsContent.Margin).Height;
if (true)
{
@@ -943,6 +943,16 @@ namespace Avalonia.Controls
_previousDetailsHeight = newValue.Height;
}
}
+ private void DetailsContent_BoundsChanged(Rect newValue)
+ {
+ if(_detailsContent != null)
+ DetailsContent_SizeChanged(newValue.Inflate(_detailsContent.Margin));
+ }
+ private void DetailsContent_MarginChanged(Thickness newValue)
+ {
+ if (_detailsContent != null)
+ DetailsContent_SizeChanged(_detailsContent.Bounds.Inflate(newValue));
+ }
//TODO Animation
// Sets AreDetailsVisible on the row and animates if necessary
@@ -997,7 +1007,7 @@ namespace Avalonia.Controls
}
}
}
-
+
internal void ApplyDetailsTemplate(bool initializeDetailsPreferredHeight)
{
if (_detailsElement != null && AreDetailsVisible)
@@ -1023,8 +1033,11 @@ namespace Avalonia.Controls
if (_detailsContent != null)
{
_detailsContentSizeSubscription =
- _detailsContent.GetObservable(BoundsProperty)
- .Subscribe(DetailsContent_SizeChanged);
+ System.Reactive.Disposables.StableCompositeDisposable.Create(
+ _detailsContent.GetObservable(BoundsProperty)
+ .Subscribe(DetailsContent_BoundsChanged),
+ _detailsContent.GetObservable(MarginProperty)
+ .Subscribe(DetailsContent_MarginChanged));
_detailsElement.Children.Add(_detailsContent);
}
}
@@ -1053,4 +1066,4 @@ namespace Avalonia.Controls
//TODO Styles
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs
index bbea3693cc..9f9fe5eae1 100644
--- a/src/Avalonia.Controls/Application.cs
+++ b/src/Avalonia.Controls/Application.cs
@@ -255,16 +255,13 @@ namespace Avalonia
if (MainWindow == null)
{
- Dispatcher.UIThread.Post(() =>
+ if (!mainWindow.IsVisible)
{
- if (!mainWindow.IsVisible)
- {
- mainWindow.Show();
- }
+ mainWindow.Show();
+ }
- MainWindow = mainWindow;
- });
- }
+ MainWindow = mainWindow;
+ }
return Run(new CancellationTokenSource());
}
@@ -362,7 +359,7 @@ namespace Avalonia
}
///
- bool IResourceProvider.TryGetResource(string key, out object value)
+ bool IResourceProvider.TryGetResource(object key, out object value)
{
value = null;
return (_resources?.TryGetResource(key, out value) ?? false) ||
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index cc9e6b7444..b09d3bddff 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -33,8 +33,6 @@ namespace Avalonia.Controls
///
public class Button : ContentControl
{
- private ICommand _command;
-
///
/// Defines the property.
///
@@ -75,6 +73,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty IsPressedProperty =
AvaloniaProperty.Register