diff --git a/.gitignore b/.gitignore
index d965a09574..640725fa26 100644
--- a/.gitignore
+++ b/.gitignore
@@ -105,6 +105,11 @@ csx
# Windows Store app package directory
AppPackages/
+# NCrunch
+_NCrunch_*/
+*.ncrunchsolution.user
+nCrunchTemp_*/
+
# Others
sql/
*.Cache
@@ -157,7 +162,8 @@ $RECYCLE.BIN/
#################
## Cake
#################
-tools/
+tools/*
+!tools/packages.config
.nuget
artifacts/
nuget
diff --git a/.gitmodules b/.gitmodules
index 0b2349ad42..6e9b10efa4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,9 +5,6 @@
path = src/Avalonia.HtmlRenderer/external
url = https://github.com/AvaloniaUI/HTML-Renderer.git
branch = perspex-pcl
-[submodule "src/Markup/Avalonia.Markup.Xaml/OmniXAML"]
- path = src/Markup/Avalonia.Markup.Xaml/OmniXAML
- url = https://github.com/AvaloniaUI/OmniXAML.git
-[submodule "src/Markup/Avalonia.Markup.Xaml/glass"]
- path = src/Markup/Avalonia.Markup.Xaml/glass
- url = https://github.com/SuperJMN/glass
+[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
diff --git a/.ncrunch/Avalonia.Android.v3.ncrunchproject b/.ncrunch/Avalonia.Android.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/Avalonia.Android.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.AndroidTestApplication.v3.ncrunchproject b/.ncrunch/Avalonia.AndroidTestApplication.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.AndroidTestApplication.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Animation.v3.ncrunchproject b/.ncrunch/Avalonia.Animation.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Animation.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Base.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..13f78c1d4c
--- /dev/null
+++ b/.ncrunch/Avalonia.Base.UnitTests.v3.ncrunchproject
@@ -0,0 +1,8 @@
+
+
+
+ LongTestTimesWithoutParallelExecution
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Base.v3.ncrunchproject b/.ncrunch/Avalonia.Base.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Base.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject b/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Benchmarks.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Cairo.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Cairo.RenderTests.v3.ncrunchproject
new file mode 100644
index 0000000000..101c806e63
--- /dev/null
+++ b/.ncrunch/Avalonia.Cairo.RenderTests.v3.ncrunchproject
@@ -0,0 +1,8 @@
+
+
+
+ AbnormalReferenceResolution
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Cairo.v3.ncrunchproject b/.ncrunch/Avalonia.Cairo.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Cairo.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Controls.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..13f78c1d4c
--- /dev/null
+++ b/.ncrunch/Avalonia.Controls.UnitTests.v3.ncrunchproject
@@ -0,0 +1,8 @@
+
+
+
+ LongTestTimesWithoutParallelExecution
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Controls.v3.ncrunchproject b/.ncrunch/Avalonia.Controls.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Controls.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Designer.v3.ncrunchproject b/.ncrunch/Avalonia.Designer.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Designer.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.DesignerSupport.TestApp.v3.ncrunchproject b/.ncrunch/Avalonia.DesignerSupport.TestApp.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/Avalonia.DesignerSupport.TestApp.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.DesignerSupport.Tests.v3.ncrunchproject b/.ncrunch/Avalonia.DesignerSupport.Tests.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/Avalonia.DesignerSupport.Tests.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.DesignerSupport.v3.ncrunchproject b/.ncrunch/Avalonia.DesignerSupport.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.DesignerSupport.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Diagnostics.v3.ncrunchproject b/.ncrunch/Avalonia.Diagnostics.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Diagnostics.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
new file mode 100644
index 0000000000..235da29767
--- /dev/null
+++ b/.ncrunch/Avalonia.Direct2D1.RenderTests.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ 1000
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Direct2D1.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Direct2D1.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Direct2D1.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Direct2D1.v3.ncrunchproject b/.ncrunch/Avalonia.Direct2D1.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Direct2D1.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.DotNetCoreRuntime.v3.ncrunchproject b/.ncrunch/Avalonia.DotNetCoreRuntime.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.DotNetCoreRuntime.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject b/.ncrunch/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject
new file mode 100644
index 0000000000..3cd9a982c9
--- /dev/null
+++ b/.ncrunch/Avalonia.DotNetFrameworkRuntime.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ False
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Gtk.v3.ncrunchproject b/.ncrunch/Avalonia.Gtk.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Gtk.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Gtk3.v3.ncrunchproject b/.ncrunch/Avalonia.Gtk3.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.Gtk3.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.HtmlRenderer.v3.ncrunchproject b/.ncrunch/Avalonia.HtmlRenderer.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.HtmlRenderer.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Input.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Input.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Input.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Input.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Input.v3.ncrunchproject b/.ncrunch/Avalonia.Input.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Input.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Interactivity.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject b/.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Interactivity.UnitTests.netcoreapp1.1.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Interactivity.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Interactivity.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Interactivity.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Interactivity.v3.ncrunchproject b/.ncrunch/Avalonia.Interactivity.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Interactivity.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Layout.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Layout.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Layout.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Layout.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Layout.v3.ncrunchproject b/.ncrunch/Avalonia.Layout.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Layout.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.LeakTests.v3.ncrunchproject b/.ncrunch/Avalonia.LeakTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.LeakTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.LinuxFramebuffer.v3.ncrunchproject b/.ncrunch/Avalonia.LinuxFramebuffer.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.LinuxFramebuffer.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Logging.Serilog.v3.ncrunchproject b/.ncrunch/Avalonia.Logging.Serilog.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Logging.Serilog.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Markup.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Markup.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Markup.Xaml.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Markup.Xaml.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.Xaml.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Markup.Xaml.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Markup.v3.ncrunchproject b/.ncrunch/Avalonia.Markup.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Markup.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.ReactiveUI.v3.ncrunchproject b/.ncrunch/Avalonia.ReactiveUI.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.ReactiveUI.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.RenderTests.v3.ncrunchproject
new file mode 100644
index 0000000000..95a483b433
--- /dev/null
+++ b/.ncrunch/Avalonia.RenderTests.v3.ncrunchproject
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Skia.Android.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.Android.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/Avalonia.Skia.Android.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Skia.Desktop.NetStandard.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.Desktop.NetStandard.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.Skia.Desktop.NetStandard.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Skia.Desktop.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.Desktop.v3.ncrunchproject
new file mode 100644
index 0000000000..ae3801f32b
--- /dev/null
+++ b/.ncrunch/Avalonia.Skia.Desktop.v3.ncrunchproject
@@ -0,0 +1,8 @@
+
+
+ True
+ False
+ True
+ x86
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject
new file mode 100644
index 0000000000..235da29767
--- /dev/null
+++ b/.ncrunch/Avalonia.Skia.RenderTests.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ 1000
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Skia.iOS.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.iOS.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/Avalonia.Skia.iOS.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Skia.v3.ncrunchproject b/.ncrunch/Avalonia.Skia.v3.ncrunchproject
new file mode 100644
index 0000000000..95a483b433
--- /dev/null
+++ b/.ncrunch/Avalonia.Skia.v3.ncrunchproject
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Styling.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Styling.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Styling.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Styling.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Styling.v3.ncrunchproject b/.ncrunch/Avalonia.Styling.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Styling.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Themes.Default.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Default.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Themes.Default.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.UnitTests.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Visuals.UnitTests.net461.v3.ncrunchproject b/.ncrunch/Avalonia.Visuals.UnitTests.net461.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Visuals.UnitTests.net461.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Visuals.UnitTests.v3.ncrunchproject b/.ncrunch/Avalonia.Visuals.UnitTests.v3.ncrunchproject
new file mode 100644
index 0000000000..ee655751a0
--- /dev/null
+++ b/.ncrunch/Avalonia.Visuals.UnitTests.v3.ncrunchproject
@@ -0,0 +1,9 @@
+
+
+
+ AbnormalReferenceResolution
+ LongTestTimesWithoutParallelExecution
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Visuals.v3.ncrunchproject b/.ncrunch/Avalonia.Visuals.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Visuals.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Win32.Interop.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.Interop.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Win32.Interop.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Win32.NetStandard.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.NetStandard.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.Win32.NetStandard.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Win32.Shared.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.Shared.v3.ncrunchproject
new file mode 100644
index 0000000000..95a483b433
--- /dev/null
+++ b/.ncrunch/Avalonia.Win32.Shared.v3.ncrunchproject
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Win32.v3.ncrunchproject b/.ncrunch/Avalonia.Win32.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Avalonia.Win32.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.iOS.v3.ncrunchproject b/.ncrunch/Avalonia.iOS.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.iOS.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.iOSTestApplication.v3.ncrunchproject b/.ncrunch/Avalonia.iOSTestApplication.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.iOSTestApplication.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/BindingTest.v3.ncrunchproject b/.ncrunch/BindingTest.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/BindingTest.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/ControlCatalog.Android.v3.ncrunchproject b/.ncrunch/ControlCatalog.Android.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/ControlCatalog.Android.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject b/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/ControlCatalog.Desktop.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject b/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/ControlCatalog.iOS.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/ControlCatalog.v3.ncrunchproject b/.ncrunch/ControlCatalog.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/ControlCatalog.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Direct3DInteropSample.v3.ncrunchproject b/.ncrunch/Direct3DInteropSample.v3.ncrunchproject
new file mode 100644
index 0000000000..6800b4a3fe
--- /dev/null
+++ b/.ncrunch/Direct3DInteropSample.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/GtkInteropDemo.v3.ncrunchproject b/.ncrunch/GtkInteropDemo.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/GtkInteropDemo.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/PlatformSupport.v3.ncrunchproject b/.ncrunch/PlatformSupport.v3.ncrunchproject
new file mode 100644
index 0000000000..95a483b433
--- /dev/null
+++ b/.ncrunch/PlatformSupport.v3.ncrunchproject
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.ncrunch/RenderHelpers.v3.ncrunchproject b/.ncrunch/RenderHelpers.v3.ncrunchproject
new file mode 100644
index 0000000000..95a483b433
--- /dev/null
+++ b/.ncrunch/RenderHelpers.v3.ncrunchproject
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/.ncrunch/RenderTest.v3.ncrunchproject b/.ncrunch/RenderTest.v3.ncrunchproject
new file mode 100644
index 0000000000..e12537d535
--- /dev/null
+++ b/.ncrunch/RenderTest.v3.ncrunchproject
@@ -0,0 +1,8 @@
+
+
+
+ MissingOrIgnoredProjectReference
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/VirtualizationTest.v3.ncrunchproject b/.ncrunch/VirtualizationTest.v3.ncrunchproject
new file mode 100644
index 0000000000..a4953e14f9
--- /dev/null
+++ b/.ncrunch/VirtualizationTest.v3.ncrunchproject
@@ -0,0 +1,6 @@
+
+
+ True
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/WindowsInteropTest.v3.ncrunchproject b/.ncrunch/WindowsInteropTest.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/WindowsInteropTest.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index af7d5dbebf..a3c02eea58 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,8 +2,14 @@ language: csharp
os:
- linux
- osx
+dist: trusty
+env:
+ global:
+ - DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+ - DOTNET_CLI_TELEMETRY_OPTOUT=1
mono:
- latest
+dotnet: 1.0.1
script:
- ./build.sh --target "Travis" --platform "Mono" --configuration "Release"
notifications:
diff --git a/Avalonia.sln b/Avalonia.sln
index ad14483b40..afaee6a907 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
+# Visual Studio 15
+VisualStudioVersion = 15.0.26228.4
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Base", "src\Avalonia.Base\Avalonia.Base.csproj", "{B09B78D8-9B26-48B0-9149-D64A2F120F3F}"
EndProject
@@ -15,9 +15,6 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Direct2D1", "src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj", "{3E908F67-5543-4879-A1DC-08EACE79B3CD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Designer", "src\Windows\Avalonia.Designer\Avalonia.Designer.csproj", "{EC42600F-049B-43FF-AED1-8314D61B2749}"
- ProjectSection(ProjectDependencies) = postProject
- {2B888490-D14A-4BCA-AB4B-48676FA93C9B} = {2B888490-D14A-4BCA-AB4B-48676FA93C9B}
- EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Input", "src\Avalonia.Input\Avalonia.Input.csproj", "{62024B2D-53EB-4638-B26B-85EEAA54866E}"
EndProject
@@ -85,9 +82,6 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Markup.UnitTests", "tests\Avalonia.Markup.UnitTests\Avalonia.Markup.UnitTests.csproj", "{8EF392D5-1416-45AA-9956-7CBBC3229E8A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BindingTest", "samples\BindingTest\BindingTest.csproj", "{08B3E6B9-1CD5-443C-9F61-6D49D1C5F162}"
- ProjectSection(ProjectDependencies) = postProject
- {B61B66A3-B82D-4875-8001-89D3394FE0C9} = {B61B66A3-B82D-4875-8001-89D3394FE0C9}
- EndProjectSection
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "RenderHelpers", "src\Shared\RenderHelpers\RenderHelpers.shproj", "{3C4C0CB4-0C0F-4450-A37B-148C84FF905F}"
EndProject
@@ -126,9 +120,6 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog", "samples\ControlCatalog\ControlCatalog.csproj", "{D0A739B9-3C68-4BA6-A328-41606954B6BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.Desktop", "samples\ControlCatalog.Desktop\ControlCatalog.Desktop.csproj", "{2B888490-D14A-4BCA-AB4B-48676FA93C9B}"
- ProjectSection(ProjectDependencies) = postProject
- {BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {BB1F7BB5-6AD4-4776-94D9-C09D0A972658}
- EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.iOS", "samples\ControlCatalog.iOS\ControlCatalog.iOS.csproj", "{57E0455D-D565-44BB-B069-EE1AA20F8337}"
EndProject
@@ -164,6 +155,44 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Skia.Desktop.NetSt
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Gtk3", "src\Gtk\Avalonia.Gtk3\Avalonia.Gtk3.csproj", "{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ControlCatalog.NetCore", "samples\ControlCatalog.NetCore\ControlCatalog.NetCore.csproj", "{39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{74487168-7D91-487E-BF93-055F2251461E}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
+ ProjectSection(SolutionItems) = preProject
+ build\JetBrains.Annotations.props = build\JetBrains.Annotations.props
+ build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props
+ build\Magick.NET-Q16-AnyCPU.props = build\Magick.NET-Q16-AnyCPU.props
+ build\Markup.props = build\Markup.props
+ build\Microsoft.CSharp.props = build\Microsoft.CSharp.props
+ build\Microsoft.Reactive.Testing.props = build\Microsoft.Reactive.Testing.props
+ build\Moq.props = build\Moq.props
+ build\NetCore.props = build\NetCore.props
+ build\Rx.props = build\Rx.props
+ build\Serilog.props = build\Serilog.props
+ build\Serilog.Sinks.Trace.props = build\Serilog.Sinks.Trace.props
+ build\SharpDX.props = build\SharpDX.props
+ build\SkiaSharp.Desktop.props = build\SkiaSharp.Desktop.props
+ build\SkiaSharp.props = build\SkiaSharp.props
+ build\Splat.props = build\Splat.props
+ build\Sprache.props = build\Sprache.props
+ build\XUnit.props = build\XUnit.props
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
+ ProjectSection(SolutionItems) = preProject
+ build\UnitTests.NetCore.targets = build\UnitTests.NetCore.targets
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.LinuxFramebuffer", "src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj", "{854568D5-13D1-4B4F-B50D-534DC7EFD3C9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Direct3DInteropSample", "samples\interop\Direct3DInteropSample\Direct3DInteropSample.csproj", "{638580B0-7910-40EF-B674-DCB34DA308CD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Win32.Interop", "src\Windows\Avalonia.Win32.Interop\Avalonia.Win32.Interop.csproj", "{CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Skia\Avalonia.Skia\Avalonia.Skia.projitems*{2f59f3d0-748d-4652-b01e-e0d954756308}*SharedItemsImports = 13
@@ -2442,6 +2471,166 @@ Global
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|Mono.Build.0 = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|x86.ActiveCfg = Release|Any CPU
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658}.Release|x86.Build.0 = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|Mono.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.AppStore|x86.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Mono.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|Mono.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Debug|x86.Build.0 = Debug|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhone.Build.0 = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Mono.ActiveCfg = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|Mono.Build.0 = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|x86.ActiveCfg = Release|Any CPU
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3}.Release|x86.Build.0 = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|Mono.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.AppStore|x86.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Mono.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|Mono.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Debug|x86.Build.0 = Debug|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhone.Build.0 = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Mono.ActiveCfg = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|Mono.Build.0 = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|x86.ActiveCfg = Release|Any CPU
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9}.Release|x86.Build.0 = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Mono.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|Mono.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Mono.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|Mono.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|x86.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.AppStore|x86.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Mono.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|Mono.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Debug|x86.Build.0 = Debug|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhone.Build.0 = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Mono.ActiveCfg = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|Mono.Build.0 = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|x86.ActiveCfg = Release|Any CPU
+ {638580B0-7910-40EF-B674-DCB34DA308CD}.Release|x86.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Ad-Hoc|x86.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|Any CPU.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhone.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|Mono.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|Mono.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|x86.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.AppStore|x86.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Mono.ActiveCfg = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|Mono.Build.0 = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Debug|x86.Build.0 = Debug|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhone.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Mono.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|Mono.Build.0 = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|x86.ActiveCfg = Release|Any CPU
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2497,5 +2686,11 @@ Global
{40759A76-D0F2-464E-8000-6FF0F5C4BD7C} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{7D2D3083-71DD-4CC9-8907-39A0D86FB322} = {3743B0F2-CC41-4F14-A8C8-267F579BF91E}
{BB1F7BB5-6AD4-4776-94D9-C09D0A972658} = {B9894058-278A-46B5-B6ED-AD613FCC03B3}
+ {39D7B147-1A5B-47C2-9D01-21FB7C47C4B3} = {9B9E3891-2366-4253-A952-D08BCEB71098}
+ {F3AC8BC1-27F5-4255-9AFC-04ABFD11683A} = {74487168-7D91-487E-BF93-055F2251461E}
+ {4D6FAF79-58B4-482F-9122-0668C346364C} = {74487168-7D91-487E-BF93-055F2251461E}
+ {854568D5-13D1-4B4F-B50D-534DC7EFD3C9} = {86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}
+ {638580B0-7910-40EF-B674-DCB34DA308CD} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
+ {CBC4FF2F-92D4-420B-BE21-9FE0B930B04E} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
EndGlobalSection
EndGlobal
diff --git a/Avalonia.sln.DotSettings b/Avalonia.sln.DotSettings
index ab21d6e50b..1fd6f8d092 100644
--- a/Avalonia.sln.DotSettings
+++ b/Avalonia.sln.DotSettings
@@ -1,4 +1,5 @@
+ ExplicitlyExcluded
ExplicitlyExcluded
ExplicitlyExcluded
HINT
diff --git a/Avalonia.v2.ncrunchsolution b/Avalonia.v2.ncrunchsolution
deleted file mode 100644
index fe4feb2cb6..0000000000
Binary files a/Avalonia.v2.ncrunchsolution and /dev/null differ
diff --git a/Avalonia.v3.ncrunchsolution b/Avalonia.v3.ncrunchsolution
new file mode 100644
index 0000000000..1b5b0c8930
--- /dev/null
+++ b/Avalonia.v3.ncrunchsolution
@@ -0,0 +1,10 @@
+
+
+
+ tests\TestFiles\**.*
+
+ True
+ .ncrunch
+ True
+
+
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index db7d129dd1..7457a1d5bb 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,26 +1,31 @@
-os: Visual Studio 2015
+os: Visual Studio 2017
platform:
- Any CPU
+skip_branch_with_pr: true
configuration:
- Release
environment:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
+ DOTNET_CLI_TELEMETRY_OPTOUT: 1
NUGET_API_KEY:
secure: Xv89dlP2MSBZKhl1nrWSxqcDgCXB0HRhOd4SWQ+jRJ7QoLxQel5mLTipXM++J3G5
NUGET_API_URL: https://www.nuget.org/api/v2/package
MYGET_API_KEY:
secure: OtVfyN3ErqQrDTnWH2HDfJDlCiu/i4/X4wFmK3ZXXP7HmCiXYPSbTjMPwwdOxRaK
MYGET_API_URL: https://www.myget.org/F/avalonia-ci/api/v2/package
+init:
+- ps: if (Test-Path env:nuget_address) {[System.IO.File]::AppendAllText("C:\Windows\System32\drivers\etc\hosts", "`n$($env:nuget_address)`tapi.nuget.org")}
install:
- if not exist gtk-sharp-2.12.26.msi appveyor DownloadFile http://download.xamarin.com/GTKforWindows/Windows/gtk-sharp-2.12.26.msi
- - msiexec /i gtk-sharp-2.12.26.msi /qn /norestart
+ - if not exist dotnet-1.0.1.exe appveyor DownloadFile https://go.microsoft.com/fwlink/?linkid=843448 -FileName "dotnet-1.0.1.exe"
+ - ps: Start-Process -FilePath "msiexec" -ArgumentList "/i gtk-sharp-2.12.26.msi /quiet /qn /norestart" -Wait
+ - ps: Start-Process -FilePath "dotnet-1.0.1.exe" -ArgumentList "/quiet" -Wait
- cmd: set PATH=%programfiles(x86)%\GtkSharp\2.12\bin\;%PATH%
before_build:
- git submodule update --init
build_script:
- ps: .\build.ps1 -Target "AppVeyor" -Platform "$env:platform" -Configuration "$env:configuration"
after_build:
-- .\packages\JetBrains.dotMemoryUnit.2.1.20150828.125449\tools\dotMemoryUnit.exe -targetExecutable="%xunit20%\xunit.console.x86.exe" -returnTargetExitCode --"tests\Avalonia.LeakTests\bin\Release\Avalonia.LeakTests.dll"
-
- "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%"
- pip install codecov
- codecov -f "./artifacts/coverage.xml"
@@ -29,5 +34,7 @@ test: off
artifacts:
- path: artifacts\nuget\*.nupkg
- path: artifacts\zip\*.zip
+ - path: artifacts\inspectcode.xml
cache:
- gtk-sharp-2.12.26.msi
+ - dotnet-1.0.1.exe
diff --git a/build.cake b/build.cake
index ee68c74bb3..6c2e554df4 100644
--- a/build.cake
+++ b/build.cake
@@ -4,12 +4,14 @@
#addin "nuget:?package=Polly&version=4.2.0"
#addin "nuget:?package=NuGet.Core&version=2.12.0"
-
+#tool "nuget:?package=xunit.runner.console&version=2.2.0"
+#tool "nuget:https://dotnet.myget.org/F/nuget-build/?package=NuGet.CommandLine&version=4.3.0-preview1-3980&prerelease"
+#tool "JetBrains.ReSharper.CommandLineTools"
///////////////////////////////////////////////////////////////////////////////
// TOOLS
///////////////////////////////////////////////////////////////////////////////
-#tool "nuget:?package=xunit.runner.console&version=2.1.0"
+#tool "nuget:?package=xunit.runner.console&version=2.2.0"
#tool "nuget:?package=OpenCover"
///////////////////////////////////////////////////////////////////////////////
@@ -96,50 +98,13 @@ Task("Clean")
CleanDirectory(parameters.TestsRoot);
});
-Task("Prepare-XBuild-Solution")
- .Does(() =>
-{
- var blacklistedProjects = new[]
- {
- "Avalonia.Win32.NetStandard",
- "Avalonia.DotNetCoreRuntime",
- "Avalonia.Skia.Desktop.NetStandard",
- "Avalonia.Gtk3"
- };
- var blacklistedGuids = System.IO.File.ReadAllLines(parameters.MSBuildSolution)
- .Where(l=>l.StartsWith("Project") && blacklistedProjects.Any(p=>l.Contains(p)))
- .Select(l => l.Split(',').Select(part => part.Trim()).FirstOrDefault(part => part.StartsWith("\"{")))
- .Where(g=>g!=null)
- .Select(l=>l.Trim(new[]{'"', '}', '{'}).ToLower()).ToArray();
-
- Console.WriteLine("Blacklisted guids are: " + string.Join(",", blacklistedGuids));
- var removeUntilEndProject = false;
-
- System.IO.File.WriteAllLines(parameters.XBuildSolution, System.IO.File.ReadAllLines(parameters.MSBuildSolution)
- .Where(l =>
- {
- if(removeUntilEndProject)
- {
- if(l.StartsWith("EndProject"))
- removeUntilEndProject = false;
- return false;
- }
-
- var blacklist = blacklistedGuids.Any(g => l.ToLower().Contains(g));
- if(blacklist && l.StartsWith("Project"))
- removeUntilEndProject = true;
-
- return !blacklist;
- }));
-});
-
Task("Restore-NuGet-Packages")
.IsDependentOn("Clean")
- .IsDependentOn("Prepare-XBuild-Solution")
+ .WithCriteria(parameters.IsRunningOnWindows)
.Does(() =>
{
var maxRetryCount = 5;
- var toolTimeout = 1d;
+ var toolTimeout = 2d;
Policy
.Handle()
.Retry(maxRetryCount, (exception, retryCount, context) => {
@@ -153,21 +118,22 @@ Task("Restore-NuGet-Packages")
toolTimeout+=0.5;
}})
.Execute(()=> {
- if(parameters.IsRunningOnWindows)
- {
NuGetRestore(parameters.MSBuildSolution, new NuGetRestoreSettings {
ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
});
- }
- else
- {
- NuGetRestore(parameters.XBuildSolution, new NuGetRestoreSettings {
- ToolTimeout = TimeSpan.FromMinutes(toolTimeout)
- });
- }
});
});
+void DotNetCoreBuild()
+{
+ DotNetCoreRestore("samples\\ControlCatalog.NetCore");
+ DotNetBuild("samples\\ControlCatalog.NetCore");
+}
+
+Task("DotNetCoreBuild")
+ .IsDependentOn("Clean")
+ .Does(() => DotNetCoreBuild());
+
Task("Build")
.IsDependentOn("Restore-NuGet-Packages")
.Does(() =>
@@ -177,40 +143,69 @@ Task("Build")
MSBuild(parameters.MSBuildSolution, settings => {
settings.SetConfiguration(parameters.Configuration);
settings.WithProperty("Platform", "\"" + parameters.Platform + "\"");
+ settings.WithProperty("UseRoslynPathHack", "true");
settings.SetVerbosity(Verbosity.Minimal);
settings.WithProperty("Windows", "True");
- settings.UseToolVersion(MSBuildToolVersion.VS2015);
+ settings.UseToolVersion(MSBuildToolVersion.VS2017);
settings.SetNodeReuse(false);
});
}
else
{
- XBuild(parameters.XBuildSolution, settings => {
- settings.SetConfiguration(parameters.Configuration);
- settings.WithProperty("Platform", "\"" + parameters.Platform + "\"");
- settings.SetVerbosity(Verbosity.Minimal);
- });
+ DotNetCoreBuild();
}
});
+void RunCoreTest(string dir, Parameters parameters, bool net461Only)
+{
+ Information("Running tests from " + dir);
+ DotNetCoreRestore(dir);
+ var frameworks = new List(){"netcoreapp1.1"};
+ if(parameters.IsRunningOnWindows)
+ frameworks.Add("net461");
+ foreach(var fw in frameworks)
+ {
+ if(fw != "net461" && net461Only)
+ continue;
+ Information("Running for " + fw);
+ DotNetCoreTest(System.IO.Path.Combine(dir, System.IO.Path.GetFileName(dir)+".csproj"),
+ new DotNetCoreTestSettings {
+ Configuration = parameters.Configuration,
+ Framework = fw
+ });
+ }
+}
+
+Task("Run-Net-Core-Unit-Tests")
+ .IsDependentOn("Clean")
+ .Does(() => {
+ RunCoreTest("./tests/Avalonia.Base.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Controls.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Input.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Interactivity.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Layout.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Markup.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Markup.Xaml.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Styling.UnitTests", parameters, false);
+ RunCoreTest("./tests/Avalonia.Visuals.UnitTests", parameters, false);
+ });
+
Task("Run-Unit-Tests")
+ .IsDependentOn("Run-Net-Core-Unit-Tests")
.IsDependentOn("Build")
+ //.IsDependentOn("Run-Leak-Tests")
.WithCriteria(() => !parameters.SkipTests)
.Does(() =>
{
+ if(!parameters.IsRunningOnWindows)
+ return;
+
var unitTests = GetDirectories("./tests/Avalonia.*.UnitTests")
.Select(dir => System.IO.Path.GetFileName(dir.FullPath))
.Where(name => parameters.IsRunningOnWindows ? true : !(name.IndexOf("Direct2D", StringComparison.OrdinalIgnoreCase) >= 0))
.Select(name => MakeAbsolute(File("./tests/" + name + "/bin/" + parameters.DirSuffix + "/" + name + ".dll")))
.ToList();
- if (parameters.IsRunningOnWindows)
- {
- var leakTests = GetFiles("./tests/Avalonia.LeakTests/bin/" + parameters.DirSuffix + "/*.LeakTests.dll");
-
- unitTests.AddRange(leakTests);
- }
-
var toolPath = (parameters.IsPlatformAnyCPU || parameters.IsPlatformX86) ?
"./tools/xunit.runner.console/tools/xunit.console.x86.exe" :
"./tools/xunit.runner.console/tools/xunit.console.exe";
@@ -236,7 +231,11 @@ Task("Run-Unit-Tests")
{
CopyDirectory(test.GetDirectory(), parameters.TestsRoot);
}
-
+
+ CopyFile(System.IO.Path.Combine(packages.NugetPackagesDir, "SkiaSharp", packages.SkiaSharpVersion,
+ "runtimes", "win7-x86", "native", "libSkiaSharp.dll"),
+ System.IO.Path.Combine(parameters.TestsRoot.ToString(), "libSkiaSharp.dll"));
+
var testsInDirectoryToRun = new List();
if(parameters.IsRunningOnWindows)
{
@@ -275,11 +274,15 @@ Task("Zip-Files")
Zip(parameters.ZipSourceControlCatalogDesktopDirs,
parameters.ZipTargetControlCatalogDesktopDirs,
GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dll") +
+ GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.config") +
+ GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.so") +
+ GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.dylib") +
GetFiles(parameters.ZipSourceControlCatalogDesktopDirs.FullPath + "/*.exe"));
});
Task("Create-NuGet-Packages")
.IsDependentOn("Run-Unit-Tests")
+ .IsDependentOn("Inspect")
.Does(() =>
{
foreach(var nuspec in packages.NuspecNuGetSettings)
@@ -327,7 +330,6 @@ Task("Publish-NuGet")
.WithCriteria(() => !parameters.IsLocalBuild)
.WithCriteria(() => !parameters.IsPullRequest)
.WithCriteria(() => parameters.IsMainRepo)
- .WithCriteria(() => parameters.IsMasterBranch)
.WithCriteria(() => parameters.IsNuGetRelease)
.Does(() =>
{
@@ -356,6 +358,78 @@ Task("Publish-NuGet")
Information("Publish-NuGet Task failed, but continuing with next Task...");
});
+Task("Run-Leak-Tests")
+ .WithCriteria(parameters.IsRunningOnWindows)
+ .IsDependentOn("Build")
+ .Does(() =>
+ {
+ DotNetCoreRestore("tests\\Avalonia.LeakTests\\toolproject\\tool.csproj");
+ DotNetBuild("tests\\Avalonia.LeakTests\\toolproject\\tool.csproj", settings => settings.SetConfiguration("Release"));
+ var report = "tests\\Avalonia.LeakTests\\bin\\Release\\report.xml";
+ if(System.IO.File.Exists(report))
+ System.IO.File.Delete(report);
+ var proc = System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
+ {
+ FileName="tests\\Avalonia.LeakTests\\toolproject\\bin\\dotMemoryUnit.exe",
+ Arguments="-targetExecutable=\"tools\\xunit.runner.console\\tools\\xunit.console.x86.exe\" -returnTargetExitCode -- tests\\Avalonia.LeakTests\\bin\\Release\\Avalonia.LeakTests.dll -xml tests\\Avalonia.LeakTests\\bin\\Release\\report.xml ",
+ UseShellExecute = false,
+ });
+ var st = System.Diagnostics.Stopwatch.StartNew();
+ while(!proc.HasExited && !System.IO.File.Exists(report))
+ {
+ if(st.Elapsed.TotalSeconds>60)
+ {
+ Error("Timed out, probably a bug in dotMemoryUnit");
+ proc.Kill();
+ throw new Exception("dotMemory issue");
+ }
+ proc.WaitForExit(100);
+ }
+ try{
+ proc.Kill();
+ }catch{}
+ var doc = System.Xml.Linq.XDocument.Load(report);
+ if(doc.Root.Descendants("assembly").Any(x=>x.Attribute("failed").Value.ToString() != "0"))
+ {
+ throw new Exception("Tests failed");
+ }
+
+ });
+
+Task("Inspect")
+ .WithCriteria(parameters.IsRunningOnWindows)
+ .IsDependentOn("Restore-NuGet-Packages")
+ .Does(() =>
+ {
+ var badIssues = new []{"PossibleNullReferenceException"};
+ var whitelist = new []{"tests", "src\\android", "src\\ios",
+ "src\\windows\\avalonia.designer", "src\\avalonia.htmlrenderer\\external",
+ "src\\markup\\avalonia.markup.xaml\\portablexaml\\portable.xaml.github"};
+ Information("Running code inspections");
+
+
+ StartProcess("tools\\JetBrains.ReSharper.CommandLineTools\\tools\\inspectcode.exe",
+ new ProcessSettings{ Arguments = "--output=artifacts\\inspectcode.xml --profile=Avalonia.sln.DotSettings Avalonia.sln" });
+ Information("Analyzing report");
+ var doc = XDocument.Parse(System.IO.File.ReadAllText("artifacts\\inspectcode.xml"));
+ var failBuild = false;
+ foreach(var xml in doc.Descendants("Issue"))
+ {
+ var typeId = xml.Attribute("TypeId").Value.ToString();
+ if(badIssues.Contains(typeId))
+ {
+ var file = xml.Attribute("File").Value.ToString().ToLower();
+ if(whitelist.Any(wh => file.StartsWith(wh)))
+ continue;
+ var line = xml.Attribute("Line").Value.ToString();
+ Error(typeId + " - " + file + " on line " + line);
+ failBuild = true;
+ }
+ }
+ if(failBuild)
+ throw new Exception("Issues found");
+ });
+
///////////////////////////////////////////////////////////////////////////////
// TARGETS
///////////////////////////////////////////////////////////////////////////////
@@ -363,16 +437,20 @@ Task("Publish-NuGet")
Task("Package")
.IsDependentOn("Create-NuGet-Packages");
-Task("Default")
- .IsDependentOn("Package");
-
+Task("Default").Does(() =>
+{
+ if(parameters.IsRunningOnWindows)
+ RunTarget("Package");
+ else
+ RunTarget("Run-Net-Core-Unit-Tests");
+});
Task("AppVeyor")
.IsDependentOn("Zip-Files")
.IsDependentOn("Publish-MyGet")
.IsDependentOn("Publish-NuGet");
Task("Travis")
- .IsDependentOn("Run-Unit-Tests");
+ .IsDependentOn("Run-Net-Core-Unit-Tests");
///////////////////////////////////////////////////////////////////////////////
// EXECUTE
diff --git a/build/Base.props b/build/Base.props
new file mode 100644
index 0000000000..6689465338
--- /dev/null
+++ b/build/Base.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/JetBrains.Annotations.props b/build/JetBrains.Annotations.props
new file mode 100644
index 0000000000..7bc12cbd84
--- /dev/null
+++ b/build/JetBrains.Annotations.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/JetBrains.dotMemoryUnit.props b/build/JetBrains.dotMemoryUnit.props
new file mode 100644
index 0000000000..b4cf4def5b
--- /dev/null
+++ b/build/JetBrains.dotMemoryUnit.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/Magick.NET-Q16-AnyCPU.props b/build/Magick.NET-Q16-AnyCPU.props
new file mode 100644
index 0000000000..ec747a17d8
--- /dev/null
+++ b/build/Magick.NET-Q16-AnyCPU.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/Markup.props b/build/Markup.props
new file mode 100644
index 0000000000..5be0cfbf0c
--- /dev/null
+++ b/build/Markup.props
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/Microsoft.CSharp.props b/build/Microsoft.CSharp.props
new file mode 100644
index 0000000000..d0fa63bc3e
--- /dev/null
+++ b/build/Microsoft.CSharp.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/Microsoft.Reactive.Testing.props b/build/Microsoft.Reactive.Testing.props
new file mode 100644
index 0000000000..5ee6df708e
--- /dev/null
+++ b/build/Microsoft.Reactive.Testing.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/Moq.props b/build/Moq.props
new file mode 100644
index 0000000000..55242d922e
--- /dev/null
+++ b/build/Moq.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/NetCore.props b/build/NetCore.props
new file mode 100644
index 0000000000..cebb02c7f5
--- /dev/null
+++ b/build/NetCore.props
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/build/Rx.props b/build/Rx.props
new file mode 100644
index 0000000000..5d74a6b214
--- /dev/null
+++ b/build/Rx.props
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/Serilog.Sinks.Trace.props b/build/Serilog.Sinks.Trace.props
new file mode 100644
index 0000000000..ef79fd7669
--- /dev/null
+++ b/build/Serilog.Sinks.Trace.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/Serilog.props b/build/Serilog.props
new file mode 100644
index 0000000000..e9bd39f6af
--- /dev/null
+++ b/build/Serilog.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/SharpDX.props b/build/SharpDX.props
new file mode 100644
index 0000000000..69aa817a01
--- /dev/null
+++ b/build/SharpDX.props
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
new file mode 100644
index 0000000000..04e8a3ad4f
--- /dev/null
+++ b/build/SkiaSharp.props
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/build/Splat.props b/build/Splat.props
new file mode 100644
index 0000000000..bc3367be01
--- /dev/null
+++ b/build/Splat.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/Sprache.props b/build/Sprache.props
new file mode 100644
index 0000000000..8ea84de163
--- /dev/null
+++ b/build/Sprache.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/build/UnitTests.NetCore.targets b/build/UnitTests.NetCore.targets
new file mode 100644
index 0000000000..13bb4ed230
--- /dev/null
+++ b/build/UnitTests.NetCore.targets
@@ -0,0 +1,28 @@
+
+
+ false
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ MinimumRecommendedRules.ruleset
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ MinimumRecommendedRules.ruleset
+
+
+
+
+
\ No newline at end of file
diff --git a/build/XUnit.props b/build/XUnit.props
new file mode 100644
index 0000000000..d59cee6536
--- /dev/null
+++ b/build/XUnit.props
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+ true
+
+
+
diff --git a/build/readme.md b/build/readme.md
new file mode 100644
index 0000000000..aed508a508
--- /dev/null
+++ b/build/readme.md
@@ -0,0 +1,27 @@
+### MSBuild Props
+
+```XML
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### MSBuild Targets
+
+```XML
+
+```
\ No newline at end of file
diff --git a/docs/guidelines/build.md b/docs/guidelines/build.md
index 12047ff357..822496814b 100644
--- a/docs/guidelines/build.md
+++ b/docs/guidelines/build.md
@@ -2,7 +2,7 @@
## Windows
-Avalonia requires at least Visual Studio 2015 to build on Windows.
+Avalonia requires at least Visual Studio 2017 to build on Windows.
### Install GTK Sharp
diff --git a/docs/index.md b/docs/index.md
index 99424e3f75..37d95b203d 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -10,7 +10,7 @@ What does alpha mean? Well, it means that it's now at a stage where you can have
## How do I try it out
-The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/a4542e8a-b56c-4295-8df1-7e220178b873).
+The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio).
This will add a Avalonia project template and a Window template to the standard Visual Studo "Add" dialog (yes, icons still to come :) ):
diff --git a/docs/tutorial/from-wpf.md b/docs/tutorial/from-wpf.md
index aa7a9bc13a..0eb6e80327 100644
--- a/docs/tutorial/from-wpf.md
+++ b/docs/tutorial/from-wpf.md
@@ -33,7 +33,7 @@ placed in a `DataTemplates` collection on each control (and on `Application`):
-
+
@@ -161,7 +161,7 @@ the same way that event class listeners are added](../spec/working-with-properti
## RenderTransforms and RenderTransformOrigin
-RenderTransformOrigins are different in WPF and Avalonia: If you apply a `RenderTransform`, keep in mind that our default value for the RenderTransformOrigin is `RelativePoint.Middle`. In WPF the default value is `RelativePoint.TopLeft` (0, 0). In controls like Viewbox (currently being developed) the same code will lead to a different rendering behavior:
+RenderTransformOrigins are different in WPF and Avalonia: If you apply a `RenderTransform`, keep in mind that our default value for the RenderTransformOrigin is `RelativePoint.Center`. In WPF the default value is `RelativePoint.TopLeft` (0, 0). In controls like Viewbox (currently being developed) the same code will lead to a different rendering behavior:
In WPF:

diff --git a/docs/tutorial/gettingstarted.md b/docs/tutorial/gettingstarted.md
index 0972d26c48..5b7fe436a7 100644
--- a/docs/tutorial/gettingstarted.md
+++ b/docs/tutorial/gettingstarted.md
@@ -4,7 +4,7 @@

-The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://visualstudiogallery.msdn.microsoft.com/e1c6ae1f-6fd9-467d-8f62-1e28b4225213).
+The easiest way to try out Avalonia is to install the [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio).
This will add a Avalonia project template and a Window template to the standard Visual Studo “Add”
dialog (yes, icons still to come :) ):
diff --git a/packages.cake b/packages.cake
index 67483c4579..0824dc6098 100644
--- a/packages.cake
+++ b/packages.cake
@@ -1,9 +1,49 @@
+using System.Xml.Linq;
+
public class Packages
{
public List NuspecNuGetSettings { get; private set; }
public FilePath[] NugetPackages { get; private set; }
public FilePath[] BinFiles { get; private set; }
-
+ public string NugetPackagesDir {get; private set;}
+ public string SkiaSharpVersion {get; private set; }
+ public string SkiaSharpLinuxVersion {get; private set; }
+ public Dictionary>> PackageVersions{get; private set;}
+
+
+
+ class DependencyBuilder : List
+ {
+ Packages _parent;
+ public DependencyBuilder(Packages parent)
+ {
+ _parent = parent;
+ }
+
+ string GetVersion(string name)
+ {
+ return _parent.PackageVersions[name].First().Item1;
+ }
+
+
+ public DependencyBuilder Dep(string name, params string[] fws)
+ {
+ if(fws.Length == 0)
+ Add(new NuSpecDependency() { Id = name, Version = GetVersion(name) });
+ foreach(var fw in fws)
+ Add(new NuSpecDependency() { Id = name, TargetFramework = fw, Version = GetVersion(name) });
+ return this;
+ }
+ public DependencyBuilder Deps(string[] fws, params string[] deps)
+ {
+ foreach(var fw in fws)
+ foreach(var name in deps)
+ Add(new NuSpecDependency() { Id = name, TargetFramework = fw, Version = GetVersion(name) });
+ return this;
+ }
+ }
+
+ //new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp1.0", Version = "4.3.0" },
public Packages(ICakeContext context, Parameters parameters)
{
// NUGET NUSPECS
@@ -20,24 +60,30 @@ public class Packages
path => path.Replace(System.IO.Path.DirectorySeparatorChar, System.IO.Path.AltDirectorySeparatorChar).ToUpperInvariant());
// Key: Package Id
- // Value is Tuple where Item1: Package Version, Item2: The packages.config file path.
+ // Value is Tuple where Item1: Package Version, Item2: The *.csproj/*.props file path.
var packageVersions = new Dictionary>>();
-
- System.IO.Directory.EnumerateFiles(((DirectoryPath)context.Directory("./src")).FullPath, "packages.config", SearchOption.AllDirectories).ToList().ForEach(fileName =>
+ PackageVersions = packageVersions;
+ System.IO.Directory.EnumerateFiles(((DirectoryPath)context.Directory("./build")).FullPath,
+ "*.props", SearchOption.AllDirectories).ToList().ForEach(fileName =>
{
if (!ignoredSubModulesPaths.Any(i => normalizePath(fileName).Contains(normalizePath(i))))
{
- var file = new PackageReferenceFile(fileName);
- foreach (PackageReference packageReference in file.GetPackageReferences())
+ var xdoc = XDocument.Load(fileName);
+ foreach (var reference in xdoc.Descendants().Where(x => x.Name.LocalName == "PackageReference"))
{
+ var name = reference.Attribute("Include").Value;
+ var versionAttribute = reference.Attribute("Version");
+ var version = versionAttribute != null
+ ? versionAttribute.Value
+ : reference.Elements().First(x=>x.Name.LocalName == "Version").Value;
IList> versions;
- packageVersions.TryGetValue(packageReference.Id, out versions);
+ packageVersions.TryGetValue(name, out versions);
if (versions == null)
{
versions = new List>();
- packageVersions[packageReference.Id] = versions;
+ packageVersions[name] = versions;
}
- versions.Add(Tuple.Create(packageReference.Version.ToString(), fileName));
+ versions.Add(Tuple.Create(version, fileName));
}
}
});
@@ -65,22 +111,33 @@ public class Packages
var SplatVersion = packageVersions["Splat"].FirstOrDefault().Item1;
var SpracheVersion = packageVersions["Sprache"].FirstOrDefault().Item1;
var SystemReactiveVersion = packageVersions["System.Reactive"].FirstOrDefault().Item1;
- var SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
+ var SystemValueTupleVersion = packageVersions["System.ValueTuple"].FirstOrDefault().Item1;
+ SkiaSharpVersion = packageVersions["SkiaSharp"].FirstOrDefault().Item1;
+ SkiaSharpLinuxVersion = packageVersions["Avalonia.Skia.Linux.Natives"].FirstOrDefault().Item1;
var SharpDXVersion = packageVersions["SharpDX"].FirstOrDefault().Item1;
var SharpDXDirect2D1Version = packageVersions["SharpDX.Direct2D1"].FirstOrDefault().Item1;
var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1;
+ var SharpDXDirect3D9Version = packageVersions["SharpDX.Direct3D9"].FirstOrDefault().Item1;
var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1;
context.Information("Package: Serilog, version: {0}", SerilogVersion);
context.Information("Package: Splat, version: {0}", SplatVersion);
context.Information("Package: Sprache, version: {0}", SpracheVersion);
context.Information("Package: System.Reactive, version: {0}", SystemReactiveVersion);
+ context.Information("Package: System.ValueTuple, version: {0}", SystemValueTupleVersion);
context.Information("Package: SkiaSharp, version: {0}", SkiaSharpVersion);
+ context.Information("Package: Avalonia.Skia.Linux.Natives, version: {0}", SkiaSharpLinuxVersion);
context.Information("Package: SharpDX, version: {0}", SharpDXVersion);
context.Information("Package: SharpDX.Direct2D1, version: {0}", SharpDXDirect2D1Version);
context.Information("Package: SharpDX.Direct3D11, version: {0}", SharpDXDirect3D11Version);
+ context.Information("Package: SharpDX.Direct3D9, version: {0}", SharpDXDirect3D9Version);
context.Information("Package: SharpDX.DXGI, version: {0}", SharpDXDXGIVersion);
+ var nugetPackagesDir = System.Environment.GetEnvironmentVariable("NUGET_HOME")
+ ?? System.IO.Path.Combine(System.Environment.GetEnvironmentVariable("USERPROFILE") ?? System.Environment.GetEnvironmentVariable("HOME"), ".nuget");
+
+ NugetPackagesDir = System.IO.Path.Combine(nugetPackagesDir, "packages");
+
var SetNuGetNuspecCommonProperties = new Action ((nuspec) => {
nuspec.Version = parameters.Version;
nuspec.Authors = new [] { "Avalonia Team" };
@@ -129,12 +186,12 @@ public class Packages
};
var coreLibrariesFiles = coreLibraries.Select((lib) => {
- return (FilePath)context.File(lib[0] + lib[1] + "/bin/" + parameters.DirSuffix + "/" + lib[1] + lib[2]);
+ return (FilePath)context.File(lib[0] + lib[1] + "/bin/" + parameters.DirSuffix + "/netstandard1.3/" + lib[1] + lib[2]);
}).ToList();
var coreLibrariesNuSpecContent = coreLibrariesFiles.Select((file) => {
return new NuSpecContent {
- Source = file.FullPath, Target = "lib/portable-windows8+net45"
+ Source = file.FullPath, Target = "lib/netstandard1.3"
};
});
@@ -161,7 +218,7 @@ public class Packages
var netCoreRuntimePlatformExtensions = new [] {".xml", ".dll"};
var netCoreRuntimePlatform = netCoreRuntimePlatformExtensions.Select(libSuffix => {
return new NuSpecContent {
- Source = ((FilePath)context.File("./src/Avalonia.DotNetCoreRuntime/bin/" + parameters.DirSuffix + "/Avalonia.DotNetCoreRuntime" + libSuffix)).FullPath,
+ Source = ((FilePath)context.File("./src/Avalonia.DotNetCoreRuntime/bin/" + parameters.DirSuffix + "/netcoreapp1.0/Avalonia.DotNetCoreRuntime" + libSuffix)).FullPath,
Target = "lib/netcoreapp1.0"
};
});
@@ -174,21 +231,25 @@ public class Packages
new NuGetPackSettings()
{
Id = "Avalonia",
- Dependencies = new []
+ Dependencies = new DependencyBuilder(this)
{
new NuSpecDependency() { Id = "Serilog", Version = SerilogVersion },
new NuSpecDependency() { Id = "Splat", Version = SplatVersion },
new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion },
new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion },
- new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp1.0", Version = "4.3.0" },
//.NET Core
+ new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp1.0", Version = "4.3.0" },
+ new NuSpecDependency() { Id = "Microsoft.Extensions.DependencyModel", TargetFramework = "netcoreapp1.0", Version = "1.1.0" },
new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netcoreapp1.0", Version = "1.6.0" },
- new NuSpecDependency() { Id = "Microsoft.NETCore.Portable.Compatibility", TargetFramework = "netcoreapp1.0", Version = "1.0.1" },
- new NuSpecDependency() { Id = "Splat", TargetFramework = "netcoreapp1.0", Version = "2.0.0" },
- new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp1.0", Version = "2.3.0" },
+ new NuSpecDependency() { Id = "Splat", TargetFramework = "netcoreapp1.0", Version = SplatVersion },
+ new NuSpecDependency() { Id = "Serilog", TargetFramework = "netcoreapp1.0", Version = SerilogVersion },
new NuSpecDependency() { Id = "Sprache", TargetFramework = "netcoreapp1.0", Version = SpracheVersion },
- new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp1.0", Version = SystemReactiveVersion }
- },
+ new NuSpecDependency() { Id = "System.Reactive", TargetFramework = "netcoreapp1.0", Version = SystemReactiveVersion },
+ }
+ .Deps(new string[]{null, "netcoreapp1.0"},
+ "System.ValueTuple", "System.ComponentModel.TypeConverter", "System.ComponentModel.Primitives",
+ "System.Runtime.Serialization.Primitives", "System.Xml.XmlDocument", "System.Xml.ReaderWriter")
+ .ToArray(),
Files = coreLibrariesNuSpecContent
.Concat(win32CoreLibrariesNuSpecContent).Concat(net45RuntimePlatform)
.Concat(netcoreappCoreLibrariesNuSpecContent).Concat(netCoreRuntimePlatform)
@@ -208,9 +269,9 @@ public class Packages
},
Files = new []
{
- new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/portable-windows8+net45" }
+ new NuSpecContent { Source = "Avalonia.HtmlRenderer.dll", Target = "lib/netstandard1.3" }
},
- BasePath = context.Directory("./src/Avalonia.HtmlRenderer/bin/" + parameters.DirSuffix),
+ BasePath = context.Directory("./src/Avalonia.HtmlRenderer/bin/" + parameters.DirSuffix + "/netstandard1.3"),
OutputDirectory = parameters.NugetRoot
}
};
@@ -324,7 +385,7 @@ public class Packages
Files = new []
{
new NuSpecContent { Source = "Avalonia.Win32/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/net45" },
- new NuSpecContent { Source = "Avalonia.Win32.NetStandard/bin/" + parameters.DirSuffix + "/Avalonia.Win32.dll", Target = "lib/netstandard1.1" }
+ new NuSpecContent { Source = "Avalonia.Win32.NetStandard/bin/" + parameters.DirSuffix + "/netstandard1.3/Avalonia.Win32.dll", Target = "lib/netstandard1.3" }
},
BasePath = context.Directory("./src/Windows"),
OutputDirectory = parameters.NugetRoot
@@ -345,9 +406,9 @@ public class Packages
},
Files = new []
{
- new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/net45" }
+ new NuSpecContent { Source = "Avalonia.Direct2D1.dll", Target = "lib/netstandard1.3" }
},
- BasePath = context.Directory("./src/Windows/Avalonia.Direct2D1/bin/" + parameters.DirSuffix),
+ BasePath = context.Directory("./src/Windows/Avalonia.Direct2D1/bin/" + parameters.DirSuffix + "/netstandard1.3"),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
@@ -379,9 +440,9 @@ public class Packages
},
Files = new []
{
- new NuSpecContent { Source = "Avalonia.Gtk3.dll", Target = "lib/netstandard1.1" }
+ new NuSpecContent { Source = "Avalonia.Gtk3.dll", Target = "lib/netstandard1.3" }
},
- BasePath = context.Directory("./src/Gtk/Avalonia.Gtk3/bin/" + parameters.DirSuffix),
+ BasePath = context.Directory("./src/Gtk/Avalonia.Gtk3/bin/" + parameters.DirSuffix + "/netstandard1.3"),
OutputDirectory = parameters.NugetRoot
},
///////////////////////////////////////////////////////////////////////////////
@@ -411,16 +472,12 @@ public class Packages
{
new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
new NuSpecDependency() { Id = "SkiaSharp", Version = SkiaSharpVersion },
- //.NET Core
- new NuSpecDependency() { Id = "Avalonia", TargetFramework = "netcoreapp1.0", Version = parameters.Version },
- new NuSpecDependency() { Id = "SkiaSharp", TargetFramework = "netcoreapp1.0", Version = SkiaSharpVersion },
- new NuSpecDependency() { Id = "NETStandard.Library", TargetFramework = "netcoreapp1.0", Version = "1.6.0" },
- new NuSpecDependency() { Id = "Microsoft.NETCore.Portable.Compatibility", TargetFramework = "netcoreapp1.0", Version = "1.0.1" }
+ new NuSpecDependency() { Id = "Avalonia.Skia.Linux.Natives", Version = SkiaSharpLinuxVersion }
},
Files = new []
{
new NuSpecContent { Source = "Avalonia.Skia.Desktop/bin/" + parameters.DirSuffixSkia + "/Avalonia.Skia.Desktop.dll", Target = "lib/net45" },
- new NuSpecContent { Source = "Avalonia.Skia.Desktop.NetStandard/bin/" + parameters.DirSuffix + "/Avalonia.Skia.Desktop.dll", Target = "lib/netcoreapp1.0" }
+ new NuSpecContent { Source = "Avalonia.Skia.Desktop.NetStandard/bin/" + parameters.DirSuffix + "/netstandard1.3/Avalonia.Skia.Desktop.dll", Target = "lib/netstandard1.3" }
},
BasePath = context.Directory("./src/Skia/"),
OutputDirectory = parameters.NugetRoot
@@ -433,11 +490,17 @@ public class Packages
Id = "Avalonia.Desktop",
Dependencies = new []
{
- new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
- new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
- new NuSpecDependency() { Id = "Avalonia.Gtk", Version = parameters.Version },
- new NuSpecDependency() { Id = "Avalonia.Cairo", Version = parameters.Version },
- new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = parameters.Version }
+ //Full .NET
+ new NuSpecDependency() { Id = "Avalonia.Direct2D1", TargetFramework="net45", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Gtk", TargetFramework="net45", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Cairo", TargetFramework="net45", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="net45", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", TargetFramework="net45", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="net45", Version = parameters.Version },
+ //.NET Core
+ new NuSpecDependency() { Id = "Avalonia.Win32", TargetFramework="netcoreapp1.0", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", TargetFramework="netcoreapp1.0", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Gtk3", TargetFramework="netcoreapp1.0", Version = parameters.Version }
},
Files = new NuSpecContent[]
{
@@ -445,6 +508,40 @@ public class Packages
},
BasePath = context.Directory("./"),
OutputDirectory = parameters.NugetRoot
+ },
+ new NuGetPackSettings()
+ {
+ Id = "Avalonia.Win32.Interoperability",
+ Dependencies = new []
+ {
+ new NuSpecDependency() { Id = "Avalonia.Win32", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Direct2D1", Version = parameters.Version },
+ new NuSpecDependency() { Id = "SharpDX.Direct3D9", Version = SharpDXDirect3D9Version },
+ },
+ Files = new []
+ {
+ new NuSpecContent { Source = "Avalonia.Win32.Interop/bin/" + parameters.DirSuffix + "/Avalonia.Win32.Interop.dll", Target = "lib/net45" }
+ },
+ BasePath = context.Directory("./src/Windows"),
+ OutputDirectory = parameters.NugetRoot
+ },
+ ///////////////////////////////////////////////////////////////////////////////
+ // Avalonia.LinuxFramebuffer
+ ///////////////////////////////////////////////////////////////////////////////
+ new NuGetPackSettings()
+ {
+ Id = "Avalonia.LinuxFramebuffer",
+ Dependencies = new []
+ {
+ new NuSpecDependency() { Id = "Avalonia", Version = parameters.Version },
+ new NuSpecDependency() { Id = "Avalonia.Skia.Desktop", Version = parameters.Version }
+ },
+ Files = new []
+ {
+ new NuSpecContent { Source = "Avalonia.LinuxFramebuffer/bin/" + parameters.DirSuffix + "/netstandard1.3/Avalonia.LinuxFramebuffer.dll", Target = "lib/netstandard1.3" }
+ },
+ BasePath = context.Directory("./src/Linux/"),
+ OutputDirectory = parameters.NugetRoot
}
};
diff --git a/parameters.cake b/parameters.cake
index 4a7270011c..12f448303e 100644
--- a/parameters.cake
+++ b/parameters.cake
@@ -75,17 +75,25 @@ public class Parameters
IsReleasable = StringComparer.OrdinalIgnoreCase.Equals(ReleasePlatform, Platform)
&& StringComparer.OrdinalIgnoreCase.Equals(ReleaseConfiguration, Configuration);
IsMyGetRelease = !IsTagged && IsReleasable;
- IsNuGetRelease = IsTagged && IsReleasable;
+
// VERSION
Version = context.Argument("force-nuget-version", context.ParseAssemblyInfo(AssemblyInfoPath).AssemblyVersion);
if (IsRunningOnAppVeyor)
{
+ string tagVersion = null;
if (IsTagged)
{
- // Use Tag Name as version
- Version = buildSystem.AppVeyor.Environment.Repository.Tag.Name;
+ var tag = buildSystem.AppVeyor.Environment.Repository.Tag.Name;
+ var nugetReleasePrefix = "nuget-release-";
+ IsNuGetRelease = IsTagged && IsReleasable && tag.StartsWith(nugetReleasePrefix);
+ if(IsNuGetRelease)
+ tagVersion = tag.Substring(nugetReleasePrefix.Length);
+ }
+ if(tagVersion != null)
+ {
+ Version = tagVersion;
}
else
{
diff --git a/readme.md b/readme.md
index 0cc2b05e9d..621037e89e 100644
--- a/readme.md
+++ b/readme.md
@@ -3,7 +3,7 @@
| Gitter Chat | Windows Build Status | Linux/Mac Build Status | Code Coverage |
|---|---|---|---|
-| [](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [](https://travis-ci.org/AvaloniaUI/Avalonia) | [](https://codecov.io/gh/AvaloniaUI/Avalonia) |
+| [](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) | [](https://ci.appveyor.com/project/AvaloniaUI/Avalonia/branch/master) | [](https://travis-ci.org/AvaloniaUI/Avalonia) | [](https://codecov.io/gh/AvaloniaUI/Avalonia) |
A multi-platform .NET UI framework. It can run on Windows, Linux, Mac OS X, iOS and Android.
@@ -42,7 +42,7 @@ using Direct2D and other operating systems using Gtk & Cairo.
Avalonia is now in alpha. What does "alpha" mean? Well, it means that it's now at a stage where you
can have a play and hopefully create simple applications. There's now a [Visual
-Studio Extension](https://visualstudiogallery.msdn.microsoft.com/e1c6ae1f-6fd9-467d-8f62-1e28b4225213)
+Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio)
containing project and item templates that will help you get started, and
there's an initial complement of controls. There's still a lot missing, and you
*will* find bugs, and the API *will* change, but this represents the first time
diff --git a/samples/BindingTest/App.config b/samples/BindingTest/App.config
index 98b10dfce2..373b3a13f8 100644
--- a/samples/BindingTest/App.config
+++ b/samples/BindingTest/App.config
@@ -1,21 +1,21 @@
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
diff --git a/samples/BindingTest/BindingTest.csproj b/samples/BindingTest/BindingTest.csproj
index 2dc0cd445b..8e78b0c2cd 100644
--- a/samples/BindingTest/BindingTest.csproj
+++ b/samples/BindingTest/BindingTest.csproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -9,10 +9,11 @@
Properties
BindingTest
BindingTest
- v4.5
+ v4.6.1
512
true
+ PackageReference
AnyCPU
@@ -37,29 +38,9 @@
-
- ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.dll
- True
-
-
- ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.FullNetFx.dll
- True
-
-
- ..\..\packages\Splat.1.6.2\lib\Net45\Splat.dll
- True
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\net45\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\net45\System.Reactive.Interfaces.dll
- True
-
@@ -92,7 +73,6 @@
Designer
-
@@ -178,11 +158,8 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/samples/BindingTest/BindingTest.v2.ncrunchproject b/samples/BindingTest/BindingTest.v2.ncrunchproject
deleted file mode 100644
index f744eecae0..0000000000
--- a/samples/BindingTest/BindingTest.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/samples/BindingTest/MainWindow.xaml b/samples/BindingTest/MainWindow.xaml
index 95f671fd84..7d633bcd0c 100644
--- a/samples/BindingTest/MainWindow.xaml
+++ b/samples/BindingTest/MainWindow.xaml
@@ -44,6 +44,8 @@
+
+
diff --git a/samples/BindingTest/ViewModels/MainWindowViewModel.cs b/samples/BindingTest/ViewModels/MainWindowViewModel.cs
index 4b58bf2279..2ec052c258 100644
--- a/samples/BindingTest/ViewModels/MainWindowViewModel.cs
+++ b/samples/BindingTest/ViewModels/MainWindowViewModel.cs
@@ -49,6 +49,9 @@ namespace BindingTest.ViewModels
Thread.Sleep(1000);
}
});
+
+ CurrentTimeObservable = Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(1))
+ .Select(x => DateTimeOffset.Now.ToString());
}
public ObservableCollection Items { get; }
@@ -85,6 +88,7 @@ namespace BindingTest.ViewModels
private set { this.RaiseAndSetIfChanged(ref _currentTime, value); }
}
+ public IObservable CurrentTimeObservable { get; }
public ReactiveCommand
\ No newline at end of file
diff --git a/samples/ControlCatalog.Android/ControlCatalog.Android.v2.ncrunchproject b/samples/ControlCatalog.Android/ControlCatalog.Android.v2.ncrunchproject
deleted file mode 100644
index e1b4d7cf28..0000000000
--- a/samples/ControlCatalog.Android/ControlCatalog.Android.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- false
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/samples/ControlCatalog.Android/GettingStarted.Xamarin b/samples/ControlCatalog.Android/GettingStarted.Xamarin
deleted file mode 100644
index e9d4f6a411..0000000000
--- a/samples/ControlCatalog.Android/GettingStarted.Xamarin
+++ /dev/null
@@ -1,4 +0,0 @@
-
- GS\Android\CS\AndroidApp\GettingStarted.html
- false
-
\ No newline at end of file
diff --git a/samples/ControlCatalog.Android/Resources/Resource.Designer.cs b/samples/ControlCatalog.Android/Resources/Resource.Designer.cs
index 96f0e76fd8..cee3331ba8 100644
--- a/samples/ControlCatalog.Android/Resources/Resource.Designer.cs
+++ b/samples/ControlCatalog.Android/Resources/Resource.Designer.cs
@@ -28,6 +28,8 @@ namespace ControlCatalog.Android
{
global::Avalonia.Android.Resource.String.ApplicationName = global::ControlCatalog.Android.Resource.String.ApplicationName;
global::Avalonia.Android.Resource.String.Hello = global::ControlCatalog.Android.Resource.String.Hello;
+ global::Avalonia.Android.Resource.String.library_name = global::ControlCatalog.Android.Resource.String.library_name;
+ global::Splat.Resource.String.library_name = global::ControlCatalog.Android.Resource.String.library_name;
}
public partial class Attribute
@@ -94,11 +96,14 @@ namespace ControlCatalog.Android
public partial class String
{
+ // aapt resource value: 0x7f040002
+ public const int ApplicationName = 2130968578;
+
// aapt resource value: 0x7f040001
- public const int ApplicationName = 2130968577;
+ public const int Hello = 2130968577;
// aapt resource value: 0x7f040000
- public const int Hello = 2130968576;
+ public const int library_name = 2130968576;
static String()
{
diff --git a/samples/ControlCatalog.Desktop/App.config b/samples/ControlCatalog.Desktop/App.config
index 2231c71e63..68403e421f 100644
--- a/samples/ControlCatalog.Desktop/App.config
+++ b/samples/ControlCatalog.Desktop/App.config
@@ -1,13 +1,21 @@
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
index ca5743dd5c..a3940a3a7d 100644
--- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
+++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -9,10 +9,11 @@
Properties
ControlCatalog.Desktop
ControlCatalog.Desktop
- v4.5
+ v4.6.1
512
true
+ PackageReference
AnyCPU
@@ -25,7 +26,7 @@
4
- AnyCPU
+ x86
pdbonly
true
bin\Release\
@@ -37,14 +38,6 @@
-
- ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.dll
- True
-
-
- ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.FullNetFx.dll
- True
-
@@ -57,7 +50,6 @@
-
@@ -149,11 +141,7 @@
-
+
+
+
\ No newline at end of file
diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.v2.ncrunchproject b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.v2.ncrunchproject
deleted file mode 100644
index e1b4d7cf28..0000000000
--- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- false
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/samples/ControlCatalog.Desktop/packages.config b/samples/ControlCatalog.Desktop/packages.config
deleted file mode 100644
index b3abe6f487..0000000000
--- a/samples/ControlCatalog.Desktop/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
new file mode 100644
index 0000000000..e0e848b91b
--- /dev/null
+++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
@@ -0,0 +1,14 @@
+
+
+
+ Exe
+ netcoreapp1.1
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs
new file mode 100644
index 0000000000..7c67a239e6
--- /dev/null
+++ b/samples/ControlCatalog.NetCore/Program.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Linq;
+using Avalonia;
+
+namespace ControlCatalog.NetCore
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if (args.Contains("--fbdev")) AppBuilder.Configure().InitializeWithLinuxFramebuffer(tl =>
+ {
+ tl.Content = new MainView();
+ System.Threading.ThreadPool.QueueUserWorkItem(_ => ConsoleSilencer());
+ });
+ else
+ AppBuilder.Configure()
+ .UsePlatformDetect()
+ .Start();
+ }
+
+ static void ConsoleSilencer()
+ {
+ Console.CursorVisible = false;
+ while (true)
+ Console.ReadKey(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/ControlCatalog.iOS/ControlCatalog.iOS.v2.ncrunchproject b/samples/ControlCatalog.iOS/ControlCatalog.iOS.v2.ncrunchproject
deleted file mode 100644
index e1b4d7cf28..0000000000
--- a/samples/ControlCatalog.iOS/ControlCatalog.iOS.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- false
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index f4a0915dd1..a75de098e8 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -1,20 +1,8 @@
-
-
-
+
- 10.0
- Debug
- AnyCPU
- {D0A739B9-3C68-4BA6-A328-41606954B6BD}
- Library
- Properties
- ControlCatalog
- ControlCatalog
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
+ netstandard1.3
+ False
+ false
true
@@ -33,6 +21,9 @@
prompt
4
+
+
+
@@ -56,6 +47,7 @@
Designer
+
Designer
@@ -106,6 +98,9 @@
CarouselPage.xaml
+
+ ContextMenuPage.xaml
+
CheckBoxPage.xaml
@@ -129,7 +124,7 @@
SliderPage.xaml
-
+
TreeViewPage.xaml
@@ -153,62 +148,20 @@
-
- {3E53A01A-B331-47F3-B828-4A5717E77A24}
- Avalonia.Markup.Xaml
-
-
- {6417E941-21BC-467B-A771-0DE389353CE6}
- Avalonia.Markup
-
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {D2221C82-4A25-4583-9B43-D791E3F6820C}
- Avalonia.Controls
-
-
- {7062AE20-5DCC-4442-9645-8195BDECE63E}
- Avalonia.Diagnostics
-
-
- {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}
- Avalonia.HtmlRenderer
-
-
- {62024B2D-53EB-4638-B26B-85EEAA54866E}
- Avalonia.Input
-
-
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Avalonia.Interactivity
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {6417B24E-49C2-4985-8DB2-3AB9D898EC91}
- Avalonia.ReactiveUI
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
-
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}
- Avalonia.Styling
-
-
- {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}
- Avalonia.Themes.Default
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -225,12 +178,5 @@
-
-
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/ControlCatalog.v2.ncrunchproject b/samples/ControlCatalog/ControlCatalog.v2.ncrunchproject
deleted file mode 100644
index f744eecae0..0000000000
--- a/samples/ControlCatalog/ControlCatalog.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 24f631a5f4..7dd026c124 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -10,6 +10,7 @@
+
diff --git a/samples/ControlCatalog/MainWindow.xaml.cs b/samples/ControlCatalog/MainWindow.xaml.cs
index c7c61e2b4e..413794dfa2 100644
--- a/samples/ControlCatalog/MainWindow.xaml.cs
+++ b/samples/ControlCatalog/MainWindow.xaml.cs
@@ -10,6 +10,7 @@ namespace ControlCatalog
{
this.InitializeComponent();
this.AttachDevTools();
+ Renderer.DrawDirtyRects = Renderer.DrawFps = true;
}
private void InitializeComponent()
diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml
new file mode 100644
index 0000000000..f029b1106f
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml
@@ -0,0 +1,36 @@
+
+
+ Context Menu
+ A right click menu that can be applied to any control.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs b/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
new file mode 100644
index 0000000000..dc73bef07a
--- /dev/null
+++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace ControlCatalog.Pages
+{
+ public class ContextMenuPage : UserControl
+ {
+ public ContextMenuPage()
+ {
+ this.InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml b/samples/ControlCatalog/Pages/MenuPage.xaml
index 98171f29d6..36adcf1b8f 100644
--- a/samples/ControlCatalog/Pages/MenuPage.xaml
+++ b/samples/ControlCatalog/Pages/MenuPage.xaml
@@ -3,33 +3,33 @@
Menu
A window menu
-
-
+
+
-
\ No newline at end of file
diff --git a/samples/ControlCatalog/packages.config b/samples/ControlCatalog/packages.config
deleted file mode 100644
index 44ff0f0628..0000000000
--- a/samples/ControlCatalog/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/samples/RenderTest/App.config b/samples/RenderTest/App.config
index 2231c71e63..68403e421f 100644
--- a/samples/RenderTest/App.config
+++ b/samples/RenderTest/App.config
@@ -1,13 +1,21 @@
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/RenderTest/App.xaml b/samples/RenderTest/App.xaml
index d9630eef58..c119f54915 100644
--- a/samples/RenderTest/App.xaml
+++ b/samples/RenderTest/App.xaml
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/samples/RenderTest/MainWindow.xaml b/samples/RenderTest/MainWindow.xaml
index ab233fd90b..1d3001f1b1 100644
--- a/samples/RenderTest/MainWindow.xaml
+++ b/samples/RenderTest/MainWindow.xaml
@@ -1,3 +1,32 @@
+ Title="Avalonia Render Test"
+ xmlns:pages="clr-namespace:RenderTest.Pages;assembly=RenderTest">
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/RenderTest/MainWindow.xaml.cs b/samples/RenderTest/MainWindow.xaml.cs
index feb121186f..76a8e81aca 100644
--- a/samples/RenderTest/MainWindow.xaml.cs
+++ b/samples/RenderTest/MainWindow.xaml.cs
@@ -2,16 +2,11 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
-using System.Reactive.Linq;
using Avalonia;
-using Avalonia.Animation;
using Avalonia.Controls;
-using Avalonia.Controls.Shapes;
-using Avalonia.Data;
-using Avalonia.Layout;
using Avalonia.Markup.Xaml;
-using Avalonia.Media;
-using Avalonia.Rendering;
+using RenderTest.ViewModels;
+using ReactiveUI;
namespace RenderTest
{
@@ -20,63 +15,17 @@ namespace RenderTest
public MainWindow()
{
this.InitializeComponent();
- this.CreateAnimations();
this.AttachDevTools();
- RendererMixin.DrawFpsCounter = true;
+
+ var vm = new MainWindowViewModel();
+ vm.WhenAnyValue(x => x.DrawDirtyRects).Subscribe(x => Renderer.DrawDirtyRects = x);
+ vm.WhenAnyValue(x => x.DrawFps).Subscribe(x => Renderer.DrawFps = x);
+ this.DataContext = vm;
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
-
- private void CreateAnimations()
- {
- const int Count = 100;
- var panel = new WrapPanel();
-
- for (var i = 0; i < Count; ++i)
- {
- var element = new Panel
- {
- Children =
- {
- new Ellipse
- {
- Width = 100,
- Height = 100,
- Fill = Brushes.Blue,
- },
- new Path
- {
- Data = StreamGeometry.Parse(
- "F1 M 16.6309,18.6563C 17.1309,8.15625 29.8809,14.1563 29.8809,14.1563C 30.8809,11.1563 34.1308,11.4063 34.1308,11.4063C 33.5,12 34.6309,13.1563 34.6309,13.1563C 32.1309,13.1562 31.1309,14.9062 31.1309,14.9062C 41.1309,23.9062 32.6309,27.9063 32.6309,27.9062C 24.6309,24.9063 21.1309,22.1562 16.6309,18.6563 Z M 16.6309,19.9063C 21.6309,24.1563 25.1309,26.1562 31.6309,28.6562C 31.6309,28.6562 26.3809,39.1562 18.3809,36.1563C 18.3809,36.1563 18,38 16.3809,36.9063C 15,36 16.3809,34.9063 16.3809,34.9063C 16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z"),
- Fill = Brushes.Green,
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center,
- RenderTransform = new ScaleTransform(2, 2),
- }
- },
- Margin = new Thickness(4),
- RenderTransform = new ScaleTransform(),
- };
-
- var start = Animate.Stopwatch.Elapsed;
- var index = i;
- var degrees = Animate.Timer
- .Select(x => (x - start).TotalSeconds)
- .Where(x => (x % Count) >= index && (x % Count) < index + 1)
- .Select(x => (x % 1) / 1);
-
- element.RenderTransform.Bind(
- ScaleTransform.ScaleXProperty,
- degrees,
- BindingPriority.Animation);
-
- panel.Children.Add(element);
- }
-
- Content = panel;
- }
}
}
diff --git a/samples/RenderTest/Pages/AnimationsPage.xaml b/samples/RenderTest/Pages/AnimationsPage.xaml
new file mode 100644
index 0000000000..6eb7067245
--- /dev/null
+++ b/samples/RenderTest/Pages/AnimationsPage.xaml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/samples/RenderTest/Pages/AnimationsPage.xaml.cs b/samples/RenderTest/Pages/AnimationsPage.xaml.cs
new file mode 100644
index 0000000000..991896c3b5
--- /dev/null
+++ b/samples/RenderTest/Pages/AnimationsPage.xaml.cs
@@ -0,0 +1,90 @@
+using System.Reactive.Linq;
+using Avalonia;
+using Avalonia.Animation;
+using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
+using Avalonia.Data;
+using Avalonia.Input;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+
+namespace RenderTest.Pages
+{
+ public class AnimationsPage : UserControl
+ {
+ public AnimationsPage()
+ {
+ this.InitializeComponent();
+ this.CreateAnimations();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private void CreateAnimations()
+ {
+ const int Count = 100;
+ var panel = new WrapPanel();
+
+ for (var i = 0; i < Count; ++i)
+ {
+ Ellipse ellipse;
+ var element = new Panel
+ {
+ Children =
+ {
+ (ellipse = new Ellipse
+ {
+ Name = $"ellipse{i}",
+ Width = 100,
+ Height = 100,
+ Fill = Brushes.Blue,
+ }),
+ new Path
+ {
+ Data = StreamGeometry.Parse(
+ "F1 M 16.6309,18.6563C 17.1309,8.15625 29.8809,14.1563 29.8809,14.1563C 30.8809,11.1563 34.1308,11.4063 34.1308,11.4063C 33.5,12 34.6309,13.1563 34.6309,13.1563C 32.1309,13.1562 31.1309,14.9062 31.1309,14.9062C 41.1309,23.9062 32.6309,27.9063 32.6309,27.9062C 24.6309,24.9063 21.1309,22.1562 16.6309,18.6563 Z M 16.6309,19.9063C 21.6309,24.1563 25.1309,26.1562 31.6309,28.6562C 31.6309,28.6562 26.3809,39.1562 18.3809,36.1563C 18.3809,36.1563 18,38 16.3809,36.9063C 15,36 16.3809,34.9063 16.3809,34.9063C 16.3809,34.9063 10.1309,30.9062 16.6309,19.9063 Z"),
+ Fill = Brushes.Green,
+ HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center,
+ VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
+ RenderTransform = new ScaleTransform(2, 2),
+ }
+ },
+ Margin = new Thickness(4),
+ RenderTransform = new ScaleTransform(),
+ };
+
+ var start = Animate.Stopwatch.Elapsed;
+ var index = i % (Count / 2);
+ var degrees = Animate.Timer
+ .Select(x => (x - start).TotalSeconds)
+ .Where(x => (x % Count) >= index && (x % Count) < index + 1)
+ .Select(x => (x % 1) / 1);
+
+ element.RenderTransform.Bind(
+ ScaleTransform.ScaleXProperty,
+ degrees,
+ BindingPriority.Animation);
+
+ ellipse.PointerEnter += Ellipse_PointerEnter;
+ ellipse.PointerLeave += Ellipse_PointerLeave;
+
+ panel.Children.Add(element);
+ }
+
+ Content = panel;
+ }
+
+ private void Ellipse_PointerEnter(object sender, PointerEventArgs e)
+ {
+ ((Ellipse)sender).Fill = Brushes.Red;
+ }
+
+ private void Ellipse_PointerLeave(object sender, PointerEventArgs e)
+ {
+ ((Ellipse)sender).Fill = Brushes.Blue;
+ }
+ }
+}
diff --git a/samples/RenderTest/Pages/ClippingPage.xaml b/samples/RenderTest/Pages/ClippingPage.xaml
new file mode 100644
index 0000000000..47e9d51e3c
--- /dev/null
+++ b/samples/RenderTest/Pages/ClippingPage.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+ Apply Geometry Clip
+
+
\ No newline at end of file
diff --git a/samples/RenderTest/Pages/ClippingPage.xaml.cs b/samples/RenderTest/Pages/ClippingPage.xaml.cs
new file mode 100644
index 0000000000..b416f12943
--- /dev/null
+++ b/samples/RenderTest/Pages/ClippingPage.xaml.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Reactive.Linq;
+using Avalonia;
+using Avalonia.Animation;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Avalonia.Markup.Xaml;
+using Avalonia.Media;
+
+namespace RenderTest.Pages
+{
+ public class ClippingPage : UserControl
+ {
+ private Geometry _clip;
+
+ public ClippingPage()
+ {
+ InitializeComponent();
+ CreateAnimations();
+ WireUpCheckbox();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ private void CreateAnimations()
+ {
+ var clipped = this.FindControl("clipChild");
+ var degrees = Animate.Timer.Select(x => x.TotalMilliseconds / 5);
+ clipped.RenderTransform = new RotateTransform();
+ clipped.RenderTransform.Bind(RotateTransform.AngleProperty, degrees, BindingPriority.Animation);
+ clipped.Bind(
+ Border.BackgroundProperty,
+ clipped.GetObservable(Control.IsPointerOverProperty)
+ .Select(x => x ? Brushes.Crimson : AvaloniaProperty.UnsetValue));
+ }
+
+ private void WireUpCheckbox()
+ {
+ var useMask = this.FindControl("useMask");
+ var clipped = this.FindControl("clipped");
+ _clip = clipped.Clip;
+ useMask.Click += (s, e) => clipped.Clip = clipped.Clip == null ? _clip : null;
+ }
+ }
+}
diff --git a/samples/RenderTest/RenderTest.csproj b/samples/RenderTest/RenderTest.csproj
index f117c76342..95f1479b6b 100644
--- a/samples/RenderTest/RenderTest.csproj
+++ b/samples/RenderTest/RenderTest.csproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -9,7 +9,7 @@
Properties
RenderTest
RenderTest
- v4.5
+ v4.6.1
512
true
@@ -37,36 +37,8 @@
-
- ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.dll
- True
-
-
- ..\..\packages\Serilog.1.5.14\lib\net45\Serilog.FullNetFx.dll
- True
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\net45\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\net45\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\net45\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\net45\System.Reactive.PlatformServices.dll
- True
-
-
- ..\..\packages\System.Reactive.Windows.Threading.3.0.0\lib\net45\System.Reactive.Windows.Threading.dll
- True
-
@@ -79,15 +51,21 @@
App.xaml
+
+ ClippingPage.xaml
+
+
+ AnimationsPage.xaml
+
MainWindow.xaml
+
-
@@ -167,6 +145,10 @@
{6417e941-21bc-467b-a771-0de389353ce6}
Avalonia.Markup
+
+ {925dd807-b651-475f-9f7c-cbeb974ce43d}
+ Avalonia.Skia.Desktop
+
{3e908f67-5543-4879-a1dc-08eace79b3cd}
Avalonia.Direct2D1
@@ -181,12 +163,24 @@
Designer
+
+
+ Designer
+
+
+
+
+ Designer
+
+
+
+
+ Designer
+
+
-
+
+
+
+
\ No newline at end of file
diff --git a/samples/RenderTest/RenderTest.v2.ncrunchproject b/samples/RenderTest/RenderTest.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/samples/RenderTest/RenderTest.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/samples/RenderTest/SideBar.xaml b/samples/RenderTest/SideBar.xaml
new file mode 100644
index 0000000000..950de71e2b
--- /dev/null
+++ b/samples/RenderTest/SideBar.xaml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
diff --git a/samples/RenderTest/ViewModels/MainWindowViewModel.cs b/samples/RenderTest/ViewModels/MainWindowViewModel.cs
new file mode 100644
index 0000000000..bd68752f66
--- /dev/null
+++ b/samples/RenderTest/ViewModels/MainWindowViewModel.cs
@@ -0,0 +1,34 @@
+using System;
+using ReactiveUI;
+
+namespace RenderTest.ViewModels
+{
+ public class MainWindowViewModel : ReactiveObject
+ {
+ private bool drawDirtyRects = true;
+ private bool drawFps = true;
+
+ public MainWindowViewModel()
+ {
+ ToggleDrawDirtyRects = ReactiveCommand.Create();
+ ToggleDrawDirtyRects.Subscribe(_ => DrawDirtyRects = !DrawDirtyRects);
+ ToggleDrawFps = ReactiveCommand.Create();
+ ToggleDrawFps.Subscribe(_ => DrawFps = !DrawFps);
+ }
+
+ public bool DrawDirtyRects
+ {
+ get { return drawDirtyRects; }
+ set { this.RaiseAndSetIfChanged(ref drawDirtyRects, value); }
+ }
+
+ public bool DrawFps
+ {
+ get { return drawFps; }
+ set { this.RaiseAndSetIfChanged(ref drawFps, value); }
+ }
+
+ public ReactiveCommand
\ No newline at end of file
diff --git a/samples/interop/WindowsInteropTest/WindowsInteropTest.v2.ncrunchproject b/samples/interop/WindowsInteropTest/WindowsInteropTest.v2.ncrunchproject
deleted file mode 100644
index e1b4d7cf28..0000000000
--- a/samples/interop/WindowsInteropTest/WindowsInteropTest.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- false
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/scripts/ReplaceNugetCache.ps1 b/scripts/ReplaceNugetCache.ps1
new file mode 100644
index 0000000000..5f678bedef
--- /dev/null
+++ b/scripts/ReplaceNugetCache.ps1
@@ -0,0 +1,5 @@
+copy ..\samples\ControlCatalog.NetCore\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore.\bin\Debug\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\
diff --git a/scripts/ReplaceNugetCache.sh b/scripts/ReplaceNugetCache.sh
new file mode 100755
index 0000000000..2ce3e7648d
--- /dev/null
+++ b/scripts/ReplaceNugetCache.sh
@@ -0,0 +1,7 @@
+ #!/usr/bin/env bash
+
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netcoreapp1.0/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia/$1/lib/netstandard1.1/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.gtk3/$1/lib/netstandard1.1/
+ cp ../samples/ControlCatalog.NetCore/bin/Debug/netcoreapp1.1/Avalonia**.dll ~/.nuget/packages/avalonia.skia.desktop/$1/lib/netstandard1.3/
+
diff --git a/scripts/ReplaceNugetCacheRelease.ps1 b/scripts/ReplaceNugetCacheRelease.ps1
new file mode 100644
index 0000000000..f3c1a0a975
--- /dev/null
+++ b/scripts/ReplaceNugetCacheRelease.ps1
@@ -0,0 +1,5 @@
+copy ..\samples\ControlCatalog.NetCore\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netcoreapp1.0\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.gtk3\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.skia.desktop\$args\lib\netstandard1.3\
+copy ..\samples\ControlCatalog.NetCore.\bin\Release\netcoreapp1.1\Avalonia**.dll ~\.nuget\packages\avalonia.win32\$args\lib\netstandard1.3\
diff --git a/src/Android/Avalonia.Android/AndroidPlatform.cs b/src/Android/Avalonia.Android/AndroidPlatform.cs
index 2089359c26..7134e7d1b4 100644
--- a/src/Android/Avalonia.Android/AndroidPlatform.cs
+++ b/src/Android/Avalonia.Android/AndroidPlatform.cs
@@ -51,14 +51,12 @@ namespace Avalonia.Android
.Bind().ToTransient()
.Bind().ToTransient()
.Bind().ToSingleton()
- .Bind().ToSingleton()
.Bind().ToConstant(Instance)
.Bind().ToConstant(new AndroidThreadingInterface())
.Bind().ToTransient()
.Bind().ToConstant(Instance)
.Bind().ToSingleton()
.Bind().ToConstant(new DefaultRenderLoop(60))
-
.Bind().ToConstant(new AssetLoader(app.GetType().Assembly));
SkiaPlatform.Initialize();
diff --git a/src/Android/Avalonia.Android/Avalonia.Android.csproj b/src/Android/Avalonia.Android/Avalonia.Android.csproj
index 3ee2f5af64..091fdcc4b5 100644
--- a/src/Android/Avalonia.Android/Avalonia.Android.csproj
+++ b/src/Android/Avalonia.Android/Avalonia.Android.csproj
@@ -1,5 +1,5 @@
-
+
Debug
AnyCPU
@@ -41,18 +41,6 @@
-
- ..\..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.3\System.Reactive.Core.dll
- True
-
-
- ..\..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.3\System.Reactive.PlatformServices.dll
- True
-
@@ -86,7 +74,6 @@
-
@@ -145,11 +132,5 @@
-
+
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/Avalonia.Android.v2.ncrunchproject b/src/Android/Avalonia.Android/Avalonia.Android.v2.ncrunchproject
deleted file mode 100644
index f744eecae0..0000000000
--- a/src/Android/Avalonia.Android/Avalonia.Android.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs b/src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs
index 9ae79efb48..d52eeb15e4 100644
--- a/src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs
+++ b/src/Android/Avalonia.Android/Platform/Input/AndroidMouseDevice.cs
@@ -4,6 +4,8 @@ namespace Avalonia.Android.Platform.Input
{
public class AndroidMouseDevice : MouseDevice
{
+ public static AndroidMouseDevice Instance { get; } = new AndroidMouseDevice();
+
public AndroidMouseDevice()
{
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
index 55e729f5a2..051a058363 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/AndroidFramebuffer.cs
@@ -2,7 +2,7 @@ using System;
using System.Runtime.InteropServices;
using Android.Runtime;
using Android.Views;
-using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Platform;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@@ -44,7 +44,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public int Width { get; }
public int Height { get; }
public int RowBytes { get; }
- public Size Dpi { get; } = new Size(96, 96);
+ public Vector Dpi { get; } = new Vector(96, 96);
public PixelFormat Format { get; }
[DllImport("android")]
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 75772be171..6c8db17c71 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -10,8 +10,10 @@ using Avalonia.Platform;
using System;
using System.Collections.Generic;
using System.Reactive.Disposables;
+using Avalonia.Android.Platform.Input;
using Avalonia.Controls;
using Avalonia.Controls.Platform.Surfaces;
+using Avalonia.Rendering;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@@ -65,6 +67,8 @@ namespace Avalonia.Android.Platform.SkiaPlatform
}
}
+ public IMouseDevice MouseDevice => AndroidMouseDevice.Instance;
+
public Action Closed { get; set; }
public Action Input { get; set; }
@@ -82,7 +86,12 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IPlatformHandle Handle => _view;
public IEnumerable Surfaces => new object[] {this};
-
+
+ public IRenderer CreateRenderer(IRenderRoot root)
+ {
+ return new ImmediateRenderer(root);
+ }
+
public virtual void Hide()
{
_view.Visibility = ViewStates.Invisible;
diff --git a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
index 702829b91c..0f90472bd0 100644
--- a/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
+++ b/src/Android/Avalonia.Android/Platform/Specific/Helpers/AndroidTouchEventsHelper.cs
@@ -71,7 +71,7 @@ namespace Avalonia.Android.Platform.Specific.Helpers
if (x <= _point.X && r >= _point.X && y <= _point.Y && b >= _point.Y)
{
var inputRoot = _getInputRoot();
- var mouseDevice = MouseDevice.Instance;
+ var mouseDevice = Avalonia.Android.Platform.Input.AndroidMouseDevice.Instance;
//in order the controls to work in a predictable way
//we need to generate mouse move before first mouse down event
diff --git a/src/Android/Avalonia.Android/Resources/Resource.Designer.cs b/src/Android/Avalonia.Android/Resources/Resource.Designer.cs
index 80cbbc51ec..e66c2800d3 100644
--- a/src/Android/Avalonia.Android/Resources/Resource.Designer.cs
+++ b/src/Android/Avalonia.Android/Resources/Resource.Designer.cs
@@ -40,11 +40,14 @@ namespace Avalonia.Android
public partial class String
{
+ // aapt resource value: 0x7f020002
+ public static int ApplicationName = 2130837506;
+
// aapt resource value: 0x7f020001
- public static int ApplicationName = 2130837505;
+ public static int Hello = 2130837505;
// aapt resource value: 0x7f020000
- public static int Hello = 2130837504;
+ public static int library_name = 2130837504;
static String()
{
diff --git a/src/Android/Avalonia.Android/packages.config b/src/Android/Avalonia.Android/packages.config
deleted file mode 100644
index 057d0855b8..0000000000
--- a/src/Android/Avalonia.Android/packages.config
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
index d09f162150..87d1f67986 100644
--- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
+++ b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
@@ -1,5 +1,5 @@
-
+
Debug
AnyCPU
@@ -64,35 +64,8 @@
-
- ..\..\..\packages\Serilog.1.5.14\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Serilog.dll
- True
-
-
- ..\..\..\packages\Splat.1.6.2\lib\monoandroid\Splat.dll
- True
-
-
- ..\..\..\packages\Sprache.2.1.0\lib\netstandard1.0\Sprache.dll
-
-
- ..\..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.3\System.Reactive.Core.dll
- True
-
-
- ..\..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.3\System.Reactive.Linq.dll
- True
-
-
- ..\..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.3\System.Reactive.PlatformServices.dll
- True
-
@@ -103,7 +76,6 @@
-
@@ -181,11 +153,8 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.v2.ncrunchproject b/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.v2.ncrunchproject
deleted file mode 100644
index e1b4d7cf28..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- true
- false
- false
- false
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs b/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
index 3fa0707176..91327cf941 100644
--- a/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
+++ b/src/Android/Avalonia.AndroidTestApplication/Resources/Resource.Designer.cs
@@ -28,6 +28,7 @@ namespace Avalonia.AndroidTestApplication
{
global::Avalonia.Android.Resource.String.ApplicationName = global::Avalonia.AndroidTestApplication.Resource.String.ApplicationName;
global::Avalonia.Android.Resource.String.Hello = global::Avalonia.AndroidTestApplication.Resource.String.Hello;
+ global::Avalonia.Android.Resource.String.library_name = global::Avalonia.AndroidTestApplication.Resource.String.library_name;
global::Splat.Resource.String.library_name = global::Avalonia.AndroidTestApplication.Resource.String.library_name;
}
diff --git a/src/Android/Avalonia.AndroidTestApplication/packages.config b/src/Android/Avalonia.AndroidTestApplication/packages.config
deleted file mode 100644
index d353146747..0000000000
--- a/src/Android/Avalonia.AndroidTestApplication/packages.config
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Animation/Avalonia.Animation.csproj b/src/Avalonia.Animation/Avalonia.Animation.csproj
index 46aac81b5a..8f832dabcf 100644
--- a/src/Avalonia.Animation/Avalonia.Animation.csproj
+++ b/src/Avalonia.Animation/Avalonia.Animation.csproj
@@ -1,20 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Library
- Properties
- Avalonia.Animation
- Avalonia.Animation
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
+ netstandard1.3
+ false
true
@@ -38,57 +25,13 @@
CS1591
true
-
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
+
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Animation/Avalonia.Animation.v2.ncrunchproject b/src/Avalonia.Animation/Avalonia.Animation.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Animation/Avalonia.Animation.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Animation/packages.config b/src/Avalonia.Animation/packages.config
deleted file mode 100644
index 9f732f1bcb..0000000000
--- a/src/Avalonia.Animation/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj
index 90550a12f2..e0d12ce262 100644
--- a/src/Avalonia.Base/Avalonia.Base.csproj
+++ b/src/Avalonia.Base/Avalonia.Base.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Library
- Properties
- Avalonia
- Avalonia.Base
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -44,118 +29,8 @@
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\JetBrains.Annotations.10.0.0\lib\portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\JetBrains.Annotations.PCL328.dll
- True
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/Avalonia.Base/Avalonia.Base.v2.ncrunchproject b/src/Avalonia.Base/Avalonia.Base.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Base/Avalonia.Base.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Base/AvaloniaDisposable.cs b/src/Avalonia.Base/AvaloniaDisposable.cs
deleted file mode 100644
index 9e43a65f26..0000000000
--- a/src/Avalonia.Base/AvaloniaDisposable.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Avalonia.Platform;
-
-namespace Avalonia
-{
- public abstract class AvaloniaDisposable : IDisposable
- {
-#if DEBUG_DISPOSE
- public string DisposedAt { get; private set; }
-#endif
-
-
- public bool IsDisposed { get; private set; }
-
- public void Dispose()
- {
- IsDisposed = true;
-#if DEBUG_DISPOSE
- DisposedAt = AvaloniaLocator.Current.GetService().GetStackTrace();
-#endif
- DoDispose();
- }
-
- protected void CheckDisposed()
- {
- if (IsDisposed)
- throw new ObjectDisposedException(GetType().FullName
-#if DEBUG_DISPOSE
- , "Disposed at: \n" + DisposedAt
-#endif
-
- );
- }
-
- protected abstract void DoDispose();
- }
-}
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 409abfe8fa..1bdf1eb5e3 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -181,6 +181,7 @@ namespace Avalonia
public void ClearValue(AvaloniaProperty property)
{
Contract.Requires(property != null);
+ VerifyAccess();
SetValue(property, AvaloniaProperty.UnsetValue);
}
@@ -193,6 +194,7 @@ namespace Avalonia
public object GetValue(AvaloniaProperty property)
{
Contract.Requires(property != null);
+ VerifyAccess();
if (property.IsDirect)
{
@@ -234,7 +236,8 @@ namespace Avalonia
public bool IsSet(AvaloniaProperty property)
{
Contract.Requires(property != null);
-
+ VerifyAccess();
+
PriorityValue value;
if (_values.TryGetValue(property, out value))
@@ -575,13 +578,13 @@ namespace Avalonia
if (notification == null)
{
- return TypeUtilities.CastOrDefault(value, type);
+ return TypeUtilities.ConvertImplicitOrDefault(value, type);
}
else
{
if (notification.HasValue)
{
- notification.SetValue(TypeUtilities.CastOrDefault(notification.Value, type));
+ notification.SetValue(TypeUtilities.ConvertImplicitOrDefault(notification.Value, type));
}
return notification;
@@ -619,14 +622,9 @@ namespace Avalonia
/// The default value.
private object GetDefaultValue(AvaloniaProperty property)
{
- if (property.Inherits && _inheritanceParent != null)
- {
- return (_inheritanceParent as AvaloniaObject).GetValueInternal(property);
- }
- else
- {
- return ((IStyledPropertyAccessor)property).GetDefaultValue(GetType());
- }
+ if (property.Inherits && _inheritanceParent is AvaloniaObject aobj)
+ return aobj.GetValueInternal(property);
+ return ((IStyledPropertyAccessor) property).GetDefaultValue(GetType());
}
///
@@ -732,7 +730,7 @@ namespace Avalonia
ThrowNotRegistered(property);
}
- if (!TypeUtilities.TryCast(property.PropertyType, value, out value))
+ if (!TypeUtilities.TryConvertImplicit(property.PropertyType, value, out value))
{
throw new ArgumentException(string.Format(
"Invalid value for Property '{0}': '{1}' ({2})",
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index 61006b1173..fb78e3b2a0 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -476,7 +476,7 @@ namespace Avalonia
/// True if the value is valid, otherwise false.
public bool IsValidValue(object value)
{
- return TypeUtilities.TryCast(PropertyType, value, out value);
+ return TypeUtilities.TryConvertImplicit(PropertyType, value, out value);
}
///
diff --git a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs
index d63a5baf16..1aa239180c 100644
--- a/src/Avalonia.Base/Collections/AvaloniaDictionary.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaDictionary.cs
@@ -103,11 +103,9 @@ namespace Avalonia.Collections
_inner = new Dictionary();
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs("Count"));
- PropertyChanged(this, new PropertyChangedEventArgs($"Item[]"));
- }
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[]"));
+
if (CollectionChanged != null)
{
@@ -144,12 +142,9 @@ namespace Avalonia.Collections
if (_inner.TryGetValue(key, out value))
{
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs("Count"));
- PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]"));
- }
-
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
+
if (CollectionChanged != null)
{
var e = new NotifyCollectionChangedEventArgs(
@@ -199,11 +194,9 @@ namespace Avalonia.Collections
private void NotifyAdd(TKey key, TValue value)
{
- if (PropertyChanged != null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs("Count"));
- PropertyChanged(this, new PropertyChangedEventArgs($"Item[{key}]"));
- }
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Count"));
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs($"Item[{key}]"));
+
if (CollectionChanged != null)
{
diff --git a/src/Avalonia.Base/Collections/AvaloniaList.cs b/src/Avalonia.Base/Collections/AvaloniaList.cs
index ace898b55f..a3c3015a38 100644
--- a/src/Avalonia.Base/Collections/AvaloniaList.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaList.cs
@@ -220,7 +220,7 @@ namespace Avalonia.Collections
///
/// Removes all items from the collection.
///
- public void Clear()
+ public virtual void Clear()
{
if (this.Count > 0)
{
diff --git a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
index ffb7199619..54cd132b95 100644
--- a/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
+++ b/src/Avalonia.Base/Collections/AvaloniaListExtensions.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
@@ -59,7 +60,8 @@ namespace Avalonia.Collections
/// the index in the collection and the item.
///
///
- /// An action called when the collection is reset.
+ /// An action called when the collection is reset. This will be followed by calls to
+ /// for each item present in the collection after the reset.
///
/// A disposable used to terminate the subscription.
public static IDisposable ForEachItem(
@@ -68,112 +70,38 @@ namespace Avalonia.Collections
Action removed,
Action reset)
{
- int index;
-
- NotifyCollectionChangedEventHandler handler = (_, e) =>
+ void Add(int index, IList items)
{
- switch (e.Action)
+ foreach (T item in items)
{
- case NotifyCollectionChangedAction.Add:
- index = e.NewStartingIndex;
-
- foreach (T item in e.NewItems)
- {
- added(index++, item);
- }
-
- break;
-
- case NotifyCollectionChangedAction.Replace:
- index = e.OldStartingIndex;
-
- foreach (T item in e.OldItems)
- {
- removed(index++, item);
- }
-
- index = e.NewStartingIndex;
-
- foreach (T item in e.NewItems)
- {
- added(index++, item);
- }
-
- break;
-
- case NotifyCollectionChangedAction.Remove:
- index = e.OldStartingIndex;
-
- foreach (T item in e.OldItems)
- {
- removed(index++, item);
- }
-
- break;
-
- case NotifyCollectionChangedAction.Reset:
- if (reset == null)
- {
- throw new InvalidOperationException(
- "Reset called on collection without reset handler.");
- }
-
- reset();
- break;
+ added(index++, item);
}
- };
+ }
- index = 0;
- foreach (T i in collection)
+ void Remove(int index, IList items)
{
- added(index++, i);
+ for (var i = items.Count - 1; i >= 0; --i)
+ {
+ removed(index + i, (T)items[i]);
+ }
}
- collection.CollectionChanged += handler;
-
- return Disposable.Create(() => collection.CollectionChanged -= handler);
- }
-
- ///
- /// Invokes an action for each item in a collection and subsequently each item added or
- /// removed from the collection.
- ///
- /// The type of the collection items.
- /// The collection.
- ///
- /// An action called initially with all items in the collection and subsequently with a
- /// list of items added to the collection. The parameters passed are the index of the
- /// first item added to the collection and the items added.
- ///
- ///
- /// An action called with all items removed from the collection. The parameters passed
- /// are the index of the first item removed from the collection and the items removed.
- ///
- ///
- /// An action called when the collection is reset.
- ///
- /// A disposable used to terminate the subscription.
- public static IDisposable ForEachItem(
- this IAvaloniaReadOnlyList collection,
- Action> added,
- Action> removed,
- Action reset)
- {
NotifyCollectionChangedEventHandler handler = (_, e) =>
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
- added(e.NewStartingIndex, e.NewItems.Cast());
+ Add(e.NewStartingIndex, e.NewItems);
break;
+ case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
- removed(e.OldStartingIndex, e.OldItems.Cast());
- added(e.NewStartingIndex, e.NewItems.Cast());
+ Remove(e.OldStartingIndex, e.OldItems);
+ Add(e.NewStartingIndex, e.NewItems);
break;
case NotifyCollectionChangedAction.Remove:
- removed(e.OldStartingIndex, e.OldItems.Cast());
+ Remove(e.OldStartingIndex, e.OldItems);
break;
case NotifyCollectionChangedAction.Reset:
@@ -184,16 +112,31 @@ namespace Avalonia.Collections
}
reset();
+ Add(0, (IList)collection);
break;
}
};
- added(0, collection);
+ Add(0, (IList)collection);
collection.CollectionChanged += handler;
return Disposable.Create(() => collection.CollectionChanged -= handler);
}
+ public static IAvaloniaReadOnlyList CreateDerivedList(
+ this IAvaloniaReadOnlyList collection,
+ Func select)
+ {
+ var result = new AvaloniaList();
+
+ collection.ForEachItem(
+ (i, item) => result.Insert(i, select(item)),
+ (i, item) => result.RemoveAt(i),
+ () => result.Clear());
+
+ return result;
+ }
+
///
/// Listens for property changed events from all items in a collection.
///
diff --git a/src/Avalonia.Base/Data/BindingNotification.cs b/src/Avalonia.Base/Data/BindingNotification.cs
index ecaf59e174..125c29b21b 100644
--- a/src/Avalonia.Base/Data/BindingNotification.cs
+++ b/src/Avalonia.Base/Data/BindingNotification.cs
@@ -44,11 +44,7 @@ namespace Avalonia.Data
public static readonly BindingNotification UnsetValue =
new BindingNotification(AvaloniaProperty.UnsetValue);
- // Null cannot be held in WeakReference as it's indistinguishable from an expired value so
- // use this value in its place.
- private static readonly object NullValue = new object();
-
- private WeakReference _value;
+ private object _value;
///
/// Initializes a new instance of the class.
@@ -56,7 +52,7 @@ namespace Avalonia.Data
/// The binding value.
public BindingNotification(object value)
{
- _value = new WeakReference(value ?? NullValue);
+ _value = value;
}
///
@@ -73,6 +69,7 @@ namespace Avalonia.Data
Error = error;
ErrorType = errorType;
+ _value = AvaloniaProperty.UnsetValue;
}
///
@@ -84,7 +81,7 @@ namespace Avalonia.Data
public BindingNotification(Exception error, BindingErrorType errorType, object fallbackValue)
: this(error, errorType)
{
- _value = new WeakReference(fallbackValue ?? NullValue);
+ _value = fallbackValue;
}
///
@@ -95,31 +92,12 @@ namespace Avalonia.Data
/// If this property is read when is false then it will return
/// .
///
- public object Value
- {
- get
- {
- if (_value != null)
- {
- object result;
-
- if (_value.TryGetTarget(out result))
- {
- return result == NullValue ? null : result;
- }
- }
-
- // There's the possibility of a race condition in that HasValue can return true,
- // and then the value is GC'd before Value is read. We should be ok though as
- // we return UnsetValue which should be a safe alternative.
- return AvaloniaProperty.UnsetValue;
- }
- }
+ public object Value => _value;
///
/// Gets a value indicating whether should be pushed to the target.
///
- public bool HasValue => _value != null;
+ public bool HasValue => _value != AvaloniaProperty.UnsetValue;
///
/// Gets the error that occurred on the source, if any.
@@ -248,7 +226,7 @@ namespace Avalonia.Data
///
public void ClearValue()
{
- _value = null;
+ _value = AvaloniaProperty.UnsetValue;
}
///
@@ -256,7 +234,7 @@ namespace Avalonia.Data
///
public void SetValue(object value)
{
- _value = new WeakReference(value ?? NullValue);
+ _value = value;
}
///
diff --git a/src/Avalonia.Base/IPriorityValueOwner.cs b/src/Avalonia.Base/IPriorityValueOwner.cs
index 57f98c0717..aeec720920 100644
--- a/src/Avalonia.Base/IPriorityValueOwner.cs
+++ b/src/Avalonia.Base/IPriorityValueOwner.cs
@@ -25,5 +25,10 @@ namespace Avalonia
/// The source of the change.
/// The notification.
void BindingNotificationReceived(PriorityValue sender, BindingNotification notification);
+
+ ///
+ /// Ensures that the current thread is the UI thread.
+ ///
+ void VerifyAccess();
}
}
diff --git a/src/Avalonia.Base/Metadata/AmbientAttribute.cs b/src/Avalonia.Base/Metadata/AmbientAttribute.cs
new file mode 100644
index 0000000000..db36953300
--- /dev/null
+++ b/src/Avalonia.Base/Metadata/AmbientAttribute.cs
@@ -0,0 +1,15 @@
+// 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;
+
+namespace Avalonia.Metadata
+{
+ ///
+ /// Defines the ambient class/property
+ ///
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, Inherited = true)]
+ public class AmbientAttribute : Attribute
+ {
+ }
+}
diff --git a/src/Avalonia.Base/Metadata/TemplateContent.cs b/src/Avalonia.Base/Metadata/TemplateContent.cs
new file mode 100644
index 0000000000..ecc16b04a2
--- /dev/null
+++ b/src/Avalonia.Base/Metadata/TemplateContent.cs
@@ -0,0 +1,15 @@
+// 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;
+
+namespace Avalonia.Metadata
+{
+ ///
+ /// Defines the property that contains the object's content in markup.
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class TemplateContentAttribute : Attribute
+ {
+ }
+}
diff --git a/src/Avalonia.Base/PriorityBindingEntry.cs b/src/Avalonia.Base/PriorityBindingEntry.cs
index 25b7bede7e..eb7cf5414c 100644
--- a/src/Avalonia.Base/PriorityBindingEntry.cs
+++ b/src/Avalonia.Base/PriorityBindingEntry.cs
@@ -92,6 +92,8 @@ namespace Avalonia
private void ValueChanged(object value)
{
+ _owner.Owner.Owner?.VerifyAccess();
+
var notification = value as BindingNotification;
if (notification != null)
diff --git a/src/Avalonia.Base/PriorityLevel.cs b/src/Avalonia.Base/PriorityLevel.cs
index 122a6df821..b25247deaf 100644
--- a/src/Avalonia.Base/PriorityLevel.cs
+++ b/src/Avalonia.Base/PriorityLevel.cs
@@ -33,7 +33,6 @@ namespace Avalonia
///
internal class PriorityLevel
{
- private PriorityValue _owner;
private object _directValue;
private int _nextIndex;
@@ -48,13 +47,18 @@ namespace Avalonia
{
Contract.Requires(owner != null);
- _owner = owner;
+ Owner = owner;
Priority = priority;
Value = _directValue = AvaloniaProperty.UnsetValue;
ActiveBindingIndex = -1;
Bindings = new LinkedList();
}
+ ///
+ /// Gets the owner of the level.
+ ///
+ public PriorityValue Owner { get; }
+
///
/// Gets the priority of this level.
///
@@ -73,7 +77,7 @@ namespace Avalonia
set
{
Value = _directValue = value;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
}
}
@@ -131,7 +135,7 @@ namespace Avalonia
{
Value = entry.Value;
ActiveBindingIndex = entry.Index;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
}
else
{
@@ -161,7 +165,7 @@ namespace Avalonia
/// The error.
public void Error(PriorityBindingEntry entry, BindingNotification error)
{
- _owner.LevelError(this, error);
+ Owner.LevelError(this, error);
}
///
@@ -175,14 +179,14 @@ namespace Avalonia
{
Value = binding.Value;
ActiveBindingIndex = binding.Index;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
return;
}
}
Value = DirectValue;
ActiveBindingIndex = -1;
- _owner.LevelValueChanged(this);
+ Owner.LevelValueChanged(this);
}
}
}
diff --git a/src/Avalonia.Base/PriorityValue.cs b/src/Avalonia.Base/PriorityValue.cs
index 3f4b405de9..c33d50ff0e 100644
--- a/src/Avalonia.Base/PriorityValue.cs
+++ b/src/Avalonia.Base/PriorityValue.cs
@@ -26,7 +26,6 @@ namespace Avalonia
///
internal class PriorityValue
{
- private readonly IPriorityValueOwner _owner;
private readonly Type _valueType;
private readonly SingleOrDictionary _levels = new SingleOrDictionary();
private object _value;
@@ -45,7 +44,7 @@ namespace Avalonia
Type valueType,
Func validate = null)
{
- _owner = owner;
+ Owner = owner;
Property = property;
_valueType = valueType;
_value = AvaloniaProperty.UnsetValue;
@@ -53,6 +52,11 @@ namespace Avalonia
_validate = validate;
}
+ ///
+ /// Gets the owner of the value.
+ ///
+ public IPriorityValueOwner Owner { get; }
+
///
/// Gets the property that the value represents.
///
@@ -188,9 +192,9 @@ namespace Avalonia
Logger.Log(
LogEventLevel.Error,
LogArea.Binding,
- _owner,
+ Owner,
"Error in binding to {Target}.{Property}: {Message}",
- _owner,
+ Owner,
Property,
error.Error.Message);
}
@@ -245,7 +249,7 @@ namespace Avalonia
value = (notification.HasValue) ? notification.Value : null;
}
- if (TypeUtilities.TryCast(_valueType, value, out castValue))
+ if (TypeUtilities.TryConvertImplicit(_valueType, value, out castValue))
{
var old = _value;
@@ -264,24 +268,24 @@ namespace Avalonia
if (notification == null || notification.HasValue)
{
- _owner?.Changed(this, old, _value);
+ Owner?.Changed(this, old, _value);
}
if (notification != null)
{
- _owner?.BindingNotificationReceived(this, notification);
+ Owner?.BindingNotificationReceived(this, notification);
}
}
else
{
Logger.Error(
LogArea.Binding,
- _owner,
+ Owner,
"Binding produced invalid value for {$Property} ({$PropertyType}): {$Value} ({$ValueType})",
Property.Name,
_valueType,
value,
- value.GetType());
+ value?.GetType());
}
}
}
diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs
index f57afcdd70..2ee7378413 100644
--- a/src/Avalonia.Base/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs
@@ -6,4 +6,5 @@ using System.Runtime.CompilerServices;
[assembly: AssemblyTitle("Avalonia.Base")]
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
+[assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
\ No newline at end of file
diff --git a/src/Avalonia.Base/Threading/Dispatcher.cs b/src/Avalonia.Base/Threading/Dispatcher.cs
index aee6a02e73..d46b7142f4 100644
--- a/src/Avalonia.Base/Threading/Dispatcher.cs
+++ b/src/Avalonia.Base/Threading/Dispatcher.cs
@@ -15,10 +15,10 @@ namespace Avalonia.Threading
/// In Avalonia, there is usually only a single in the application -
/// the one for the UI thread, retrieved via the property.
///
- public class Dispatcher
+ public class Dispatcher : IDispatcher
{
- private readonly IPlatformThreadingInterface _platform;
private readonly JobRunner _jobRunner;
+ private IPlatformThreadingInterface _platform;
public static Dispatcher UIThread { get; } =
new Dispatcher(AvaloniaLocator.Current.GetService());
@@ -26,22 +26,31 @@ namespace Avalonia.Threading
public Dispatcher(IPlatformThreadingInterface platform)
{
_platform = platform;
- if(_platform == null)
- //TODO: Unit test mode, fix that somehow
- return;
_jobRunner = new JobRunner(platform);
- _platform.Signaled += _jobRunner.RunJobs;
+
+ if (_platform != null)
+ {
+ _platform.Signaled += _jobRunner.RunJobs;
+ }
}
+ ///
+ /// Checks that the current thread is the UI thread.
+ ///
public bool CheckAccess() => _platform?.CurrentThreadIsLoopThread ?? true;
+ ///
+ /// Checks that the current thread is the UI thread and throws if not.
+ ///
+ ///
+ /// The current thread is not the UI thread.
+ ///
public void VerifyAccess()
{
if (!CheckAccess())
throw new InvalidOperationException("Call from invalid thread");
}
-
///
/// Runs the dispatcher's main loop.
///
@@ -63,25 +72,35 @@ namespace Avalonia.Threading
_jobRunner?.RunJobs();
}
- ///
- /// Invokes a method on the dispatcher thread.
- ///
- /// The method.
- /// The priority with which to invoke the method.
- /// A task that can be used to track the method's execution.
+ ///
public Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
return _jobRunner?.InvokeAsync(action, priority);
}
- ///
- /// Post action that will be invoked on main thread
- ///
- /// The method.
- /// The priority with which to invoke the method.
+ ///
public void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
{
_jobRunner?.Post(action, priority);
}
+
+ ///
+ /// Allows unit tests to change the platform threading interface.
+ ///
+ internal void UpdateServices()
+ {
+ if (_platform != null)
+ {
+ _platform.Signaled -= _jobRunner.RunJobs;
+ }
+
+ _platform = AvaloniaLocator.Current.GetService();
+ _jobRunner.UpdateServices();
+
+ if (_platform != null)
+ {
+ _platform.Signaled += _jobRunner.RunJobs;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Threading/IDispatcher.cs b/src/Avalonia.Base/Threading/IDispatcher.cs
new file mode 100644
index 0000000000..6301015a9a
--- /dev/null
+++ b/src/Avalonia.Base/Threading/IDispatcher.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Avalonia.Threading
+{
+ ///
+ /// Dispatches jobs to a thread.
+ ///
+ public interface IDispatcher
+ {
+ ///
+ /// Determines whether the calling thread is the thread associated with this .
+ ///
+ /// True if he calling thread is the thread associated with the dispatched, otherwise false.
+ bool CheckAccess();
+
+ ///
+ /// Throws an exception if the calling thread is not the thread associated with this .
+ ///
+ void VerifyAccess();
+
+ ///
+ /// Invokes a method on the dispatcher thread.
+ ///
+ /// The method.
+ /// The priority with which to invoke the method.
+ /// A task that can be used to track the method's execution.
+ void InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
+
+ ///
+ /// Post action that will be invoked on main thread
+ ///
+ /// The method.
+ /// The priority with which to invoke the method.
+ // TODO: The naming of this method is confusing: the Async suffix usually means return a task.
+ // Remove this and rename InvokeTaskAsync as InvokeAsync. See #816.
+ Task InvokeTaskAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Base/Threading/JobRunner.cs b/src/Avalonia.Base/Threading/JobRunner.cs
index 655ef34288..e212cd9a2e 100644
--- a/src/Avalonia.Base/Threading/JobRunner.cs
+++ b/src/Avalonia.Base/Threading/JobRunner.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using System.Threading;
using System.Threading.Tasks;
using Avalonia.Platform;
@@ -14,8 +13,8 @@ namespace Avalonia.Threading
///
internal class JobRunner
{
- private readonly IPlatformThreadingInterface _platform;
private readonly Queue _queue = new Queue();
+ private IPlatformThreadingInterface _platform;
public JobRunner(IPlatformThreadingInterface platform)
{
@@ -82,6 +81,14 @@ namespace Avalonia.Threading
AddJob(new Job(action, priority, true));
}
+ ///
+ /// Allows unit tests to change the platform threading interface.
+ ///
+ internal void UpdateServices()
+ {
+ _platform = AvaloniaLocator.Current.GetService();
+ }
+
private void AddJob(Job job)
{
var needWake = false;
@@ -91,7 +98,7 @@ namespace Avalonia.Threading
_queue.Enqueue(job);
}
if (needWake)
- _platform.Signal();
+ _platform?.Signal();
}
///
diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs
index 7295bfa7ab..dd93811498 100644
--- a/src/Avalonia.Base/Utilities/TypeUtilities.cs
+++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs
@@ -14,17 +14,61 @@ namespace Avalonia.Utilities
///
public static class TypeUtilities
{
- private static readonly Dictionary> Conversions = new Dictionary>()
+ private static int[] Conversions =
{
- { typeof(decimal), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char) } },
- { typeof(double), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },
- { typeof(float), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(char), typeof(float) } },
- { typeof(ulong), new List { typeof(byte), typeof(ushort), typeof(uint), typeof(char) } },
- { typeof(long), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(char) } },
- { typeof(uint), new List { typeof(byte), typeof(ushort), typeof(char) } },
- { typeof(int), new List { typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(char) } },
- { typeof(ushort), new List { typeof(byte), typeof(char) } },
- { typeof(short), new List { typeof(byte) } }
+ 0b101111111111101, // Boolean
+ 0b100001111111110, // Char
+ 0b101111111111111, // SByte
+ 0b101111111111111, // Byte
+ 0b101111111111111, // Int16
+ 0b101111111111111, // UInt16
+ 0b101111111111111, // Int32
+ 0b101111111111111, // UInt32
+ 0b101111111111111, // Int64
+ 0b101111111111111, // UInt64
+ 0b101111111111101, // Single
+ 0b101111111111101, // Double
+ 0b101111111111101, // Decimal
+ 0b110000000000000, // DateTime
+ 0b111111111111111, // String
+ };
+
+ private static int[] ImplicitConversions =
+ {
+ 0b000000000000001, // Boolean
+ 0b001110111100010, // Char
+ 0b001110101010100, // SByte
+ 0b001111111111000, // Byte
+ 0b001110101010000, // Int16
+ 0b001111111100000, // UInt16
+ 0b001110101000000, // Int32
+ 0b001111110000000, // UInt32
+ 0b001110100000000, // Int64
+ 0b001111000000000, // UInt64
+ 0b000110000000000, // Single
+ 0b000100000000000, // Double
+ 0b001000000000000, // Decimal
+ 0b010000000000000, // DateTime
+ 0b100000000000000, // String
+ };
+
+ private static Type[] InbuiltTypes =
+ {
+ typeof(Boolean),
+ typeof(Char),
+ typeof(SByte),
+ typeof(Byte),
+ typeof(Int16),
+ typeof(UInt16),
+ typeof(Int32),
+ typeof(UInt32),
+ typeof(Int64),
+ typeof(UInt64),
+ typeof(Single),
+ typeof(Double),
+ typeof(Decimal),
+ typeof(DateTime),
+ typeof(String),
};
private static readonly Type[] NumericTypes = new[]
@@ -54,49 +98,104 @@ namespace Avalonia.Utilities
}
///
- /// Try to cast a value to a type, using implicit conversions if possible.
+ /// Try to convert a value to a type by any means possible.
///
/// The type to cast to.
/// The value to cast.
+ /// The culture to use.
/// If sucessful, contains the cast value.
/// True if the cast was sucessful, otherwise false.
- public static bool TryCast(Type to, object value, out object result)
+ public static bool TryConvert(Type to, object value, CultureInfo culture, out object result)
{
- Contract.Requires(to != null);
-
if (value == null)
{
result = null;
return AcceptsNull(to);
}
- var from = value.GetType();
-
if (value == AvaloniaProperty.UnsetValue)
{
result = value;
return true;
}
- else if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo()))
+
+ var from = value.GetType();
+ var fromTypeInfo = from.GetTypeInfo();
+ var toTypeInfo = to.GetTypeInfo();
+
+ if (toTypeInfo.IsAssignableFrom(fromTypeInfo))
{
result = value;
return true;
}
- else if (Conversions.ContainsKey(to) && Conversions[to].Contains(from))
+
+ if (to == typeof(string))
{
- result = Convert.ChangeType(value, to);
+ result = Convert.ToString(value);
return true;
}
- else
+
+ if (toTypeInfo.IsEnum && from == typeof(string))
+ {
+ if (Enum.IsDefined(to, (string)value))
+ {
+ result = Enum.Parse(to, (string)value);
+ return true;
+ }
+ }
+
+ if (!fromTypeInfo.IsEnum && toTypeInfo.IsEnum)
{
- var cast = from.GetRuntimeMethods()
- .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to);
+ result = null;
+
+ if (TryConvert(Enum.GetUnderlyingType(to), value, culture, out object enumValue))
+ {
+ result = Enum.ToObject(to, enumValue);
+ return true;
+ }
+ }
- if (cast != null)
+ if (fromTypeInfo.IsEnum && IsNumeric(to))
+ {
+ try
{
- result = cast.Invoke(null, new[] { value });
+ result = Convert.ChangeType((int)value, to, culture);
return true;
}
+ catch
+ {
+ result = null;
+ return false;
+ }
+ }
+
+ var convertableFrom = Array.IndexOf(InbuiltTypes, from);
+ var convertableTo = Array.IndexOf(InbuiltTypes, to);
+
+ if (convertableFrom != -1 && convertableTo != -1)
+ {
+ if ((Conversions[convertableFrom] & 1 << convertableTo) != 0)
+ {
+ try
+ {
+ result = Convert.ChangeType(value, to, culture);
+ return true;
+ }
+ catch
+ {
+ result = null;
+ return false;
+ }
+ }
+ }
+
+ var cast = from.GetRuntimeMethods()
+ .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to);
+
+ if (cast != null)
+ {
+ result = cast.Invoke(null, new[] { value });
+ return true;
}
result = null;
@@ -104,15 +203,14 @@ namespace Avalonia.Utilities
}
///
- /// Try to convert a value to a type, using if possible,
- /// otherwise using .
+ /// Try to convert a value to a type using the implicit conversions allowed by the C#
+ /// language.
///
/// The type to cast to.
/// The value to cast.
- /// The culture to use.
/// If sucessful, contains the cast value.
/// True if the cast was sucessful, otherwise false.
- public static bool TryConvert(Type to, object value, CultureInfo culture, out object result)
+ public static bool TryConvertImplicit(Type to, object value, out object result)
{
if (value == null)
{
@@ -120,54 +218,44 @@ namespace Avalonia.Utilities
return AcceptsNull(to);
}
- var from = value.GetType();
-
if (value == AvaloniaProperty.UnsetValue)
{
result = value;
return true;
}
- if (to.GetTypeInfo().IsAssignableFrom(from.GetTypeInfo()))
- {
- result = value;
- return true;
- }
+ var from = value.GetType();
+ var fromTypeInfo = from.GetTypeInfo();
+ var toTypeInfo = to.GetTypeInfo();
- if (to == typeof(string))
+ if (toTypeInfo.IsAssignableFrom(fromTypeInfo))
{
- result = Convert.ToString(value);
+ result = value;
return true;
}
- if (to.GetTypeInfo().IsEnum && from == typeof(string))
- {
- if (Enum.IsDefined(to, (string)value))
- {
- result = Enum.Parse(to, (string)value);
- return true;
- }
- }
-
- bool containsFrom = Conversions.ContainsKey(from);
- bool containsTo = Conversions.ContainsKey(to);
+ var convertableFrom = Array.IndexOf(InbuiltTypes, from);
+ var convertableTo = Array.IndexOf(InbuiltTypes, to);
- if ((containsFrom && containsTo) || (from == typeof(string) && containsTo))
+ if (convertableFrom != -1 && convertableTo != -1)
{
- try
- {
- result = Convert.ChangeType(value, to, culture);
- return true;
- }
- catch
+ if ((ImplicitConversions[convertableFrom] & 1 << convertableTo) != 0)
{
- result = null;
- return false;
+ try
+ {
+ result = Convert.ChangeType(value, to, CultureInfo.InvariantCulture);
+ return true;
+ }
+ catch
+ {
+ result = null;
+ return false;
+ }
}
}
var cast = from.GetRuntimeMethods()
- .FirstOrDefault(m => (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.ReturnType == to);
+ .FirstOrDefault(m => m.Name == "op_Implicit" && m.ReturnType == to);
if (cast != null)
{
@@ -180,29 +268,28 @@ namespace Avalonia.Utilities
}
///
- /// Casts a value to a type, returning the default for that type if the value could not be
- /// cast.
+ /// Convert a value to a type by any means possible, returning the default for that type
+ /// if the value could not be converted.
///
/// The value to cast.
/// The type to cast to..
+ /// The culture to use.
/// A value of .
- public static object CastOrDefault(object value, Type type)
+ public static object ConvertOrDefault(object value, Type type, CultureInfo culture)
{
- var typeInfo = type.GetTypeInfo();
- object result;
+ return TryConvert(type, value, culture, out object result) ? result : Default(type);
+ }
- if (TypeUtilities.TryCast(type, value, out result))
- {
- return result;
- }
- else if (typeInfo.IsValueType)
- {
- return Activator.CreateInstance(type);
- }
- else
- {
- return null;
- }
+ ///
+ /// Convert a value to a type using the implicit conversions allowed by the C# language or
+ /// return the default for the type if the value could not be converted.
+ ///
+ /// The value to cast.
+ /// The type to cast to..
+ /// A value of .
+ public static object ConvertImplicitOrDefault(object value, Type type)
+ {
+ return TryConvertImplicit(type, value, out object result) ? result : Default(type);
}
///
diff --git a/src/Avalonia.Base/Utilities/WeakObservable.cs b/src/Avalonia.Base/Utilities/WeakObservable.cs
index c261cc0520..b1fe78c206 100644
--- a/src/Avalonia.Base/Utilities/WeakObservable.cs
+++ b/src/Avalonia.Base/Utilities/WeakObservable.cs
@@ -16,12 +16,13 @@ namespace Avalonia.Utilities
/// Converts a .NET event conforming to the standard .NET event pattern into an observable
/// sequence, subscribing weakly.
///
+ /// The type of target.
/// The type of the event args.
/// Object instance that exposes the event to convert.
/// Name of the event to convert.
///
- public static IObservable> FromEventPattern(
- object target,
+ public static IObservable> FromEventPattern(
+ TTarget target,
string eventName)
where TEventArgs : EventArgs
{
diff --git a/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs b/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
index 356be2ba31..f1e8fa6f9b 100644
--- a/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
+++ b/src/Avalonia.Base/Utilities/WeakSubscriptionManager.cs
@@ -17,22 +17,23 @@ namespace Avalonia.Utilities
///
/// Subscribes to an event on an object using a weak subscription.
///
- /// The type of the event arguments.
+ /// The type of the target.
+ /// The type of the event arguments.
/// The event source.
/// The name of the event.
/// The subscriber.
- public static void Subscribe(object target, string eventName, IWeakSubscriber subscriber)
- where T : EventArgs
+ public static void Subscribe(TTarget target, string eventName, IWeakSubscriber subscriber)
+ where TEventArgs : EventArgs
{
- var dic = SubscriptionTypeStorage.Subscribers.GetOrCreateValue(target);
- Subscription sub;
+ var dic = SubscriptionTypeStorage.Subscribers.GetOrCreateValue(target);
+ Subscription sub;
if (!dic.TryGetValue(eventName, out sub))
{
- dic[eventName] = sub = new Subscription(dic, target, eventName);
+ dic[eventName] = sub = new Subscription(dic, typeof(TTarget), target, eventName);
}
- sub.Add(new WeakReference>(subscriber));
+ sub.Add(new WeakReference>(subscriber));
}
///
@@ -84,19 +85,18 @@ namespace Avalonia.Utilities
private WeakReference>[] _data = new WeakReference>[16];
private int _count = 0;
- public Subscription(SubscriptionDic sdic, object target, string eventName)
+ public Subscription(SubscriptionDic sdic, Type targetType, object target, string eventName)
{
_sdic = sdic;
_target = target;
_eventName = eventName;
- var t = target.GetType();
Dictionary evDic;
- if (!Accessors.TryGetValue(t, out evDic))
- Accessors[t] = evDic = new Dictionary();
+ if (!Accessors.TryGetValue(targetType, out evDic))
+ Accessors[targetType] = evDic = new Dictionary();
if (!evDic.TryGetValue(eventName, out _info))
{
- var ev = t.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
+ var ev = targetType.GetRuntimeEvents().FirstOrDefault(x => x.Name == eventName);
if (ev == null)
{
diff --git a/src/Avalonia.Base/packages.config b/src/Avalonia.Base/packages.config
deleted file mode 100644
index c372c92f3f..0000000000
--- a/src/Avalonia.Base/packages.config
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Controls/AppBuilderBase.cs b/src/Avalonia.Controls/AppBuilderBase.cs
index 97de093a59..1610d33f9b 100644
--- a/src/Avalonia.Controls/AppBuilderBase.cs
+++ b/src/Avalonia.Controls/AppBuilderBase.cs
@@ -55,8 +55,7 @@ namespace Avalonia.Controls
public Action AfterSetupCallback { get; private set; } = builder => { };
///
- /// Gets or sets a method to call before is called on the
- /// .
+ /// Gets or sets a method to call before Startis called on the .
///
public Action BeforeStartCallback { get; private set; } = builder => { };
@@ -94,8 +93,7 @@ namespace Avalonia.Controls
protected TAppBuilder Self => (TAppBuilder) this;
///
- /// Registers a callback to call before is called on the
- /// .
+ /// Registers a callback to call before Start is called on the .
///
/// The callback.
/// An instance.
@@ -129,6 +127,24 @@ namespace Avalonia.Controls
Instance.Run(window);
}
+ ///
+ /// Starts the application with the provided instance of .
+ ///
+ /// The window type.
+ /// Instance of type TMainWindow to use when starting the app
+ /// A delegate that will be called to create a data context for the window (optional).
+ public void Start(TMainWindow mainWindow, Func dataContextProvider = null)
+ where TMainWindow : Window
+ {
+ Setup();
+ BeforeStartCallback(Self);
+
+ if (dataContextProvider != null)
+ mainWindow.DataContext = dataContextProvider();
+ mainWindow.Show();
+ Instance.Run(mainWindow);
+ }
+
///
/// Sets up the platform-specific services for the application, but does not run it.
///
diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj
index 6119103e6d..037546b186 100644
--- a/src/Avalonia.Controls/Avalonia.Controls.csproj
+++ b/src/Avalonia.Controls/Avalonia.Controls.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {D2221C82-4A25-4583-9B43-D791E3F6820C}
- Library
- Properties
- Avalonia.Controls
- Avalonia.Controls
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -44,239 +29,16 @@
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\JetBrains.Annotations.10.0.0\lib\portable-net4+sl5+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\JetBrains.Annotations.PCL328.dll
- True
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
+
+
+
+
+
+
+
-
-
-
-
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {62024B2D-53EB-4638-B26B-85EEAA54866E}
- Avalonia.Input
-
-
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Avalonia.Interactivity
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
-
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}
- Avalonia.Styling
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Avalonia.Controls.v2.ncrunchproject b/src/Avalonia.Controls/Avalonia.Controls.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Controls/Avalonia.Controls.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Button.cs b/src/Avalonia.Controls/Button.cs
index 8f617466ed..78bbd836be 100644
--- a/src/Avalonia.Controls/Button.cs
+++ b/src/Avalonia.Controls/Button.cs
@@ -207,7 +207,11 @@ namespace Avalonia.Controls
/// The event args.
protected virtual void OnClick(RoutedEventArgs e)
{
- Command?.Execute(CommandParameter);
+ if (Command != null)
+ {
+ Command.Execute(CommandParameter);
+ e.Handled = true;
+ }
}
///
@@ -215,28 +219,34 @@ namespace Avalonia.Controls
{
base.OnPointerPressed(e);
- PseudoClasses.Add(":pressed");
- e.Device.Capture(this);
- e.Handled = true;
-
- if (ClickMode == ClickMode.Press)
+ if (e.MouseButton == MouseButton.Left)
{
- RaiseClickEvent();
+ PseudoClasses.Add(":pressed");
+ e.Device.Capture(this);
+ e.Handled = true;
+
+ if (ClickMode == ClickMode.Press)
+ {
+ RaiseClickEvent();
+ }
}
}
///
- protected override void OnPointerReleased(PointerEventArgs e)
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
- e.Device.Capture(null);
- PseudoClasses.Remove(":pressed");
- e.Handled = true;
-
- if (ClickMode == ClickMode.Release && Classes.Contains(":pointerover"))
+ if (e.MouseButton == MouseButton.Left)
{
- RaiseClickEvent();
+ e.Device.Capture(null);
+ PseudoClasses.Remove(":pressed");
+ e.Handled = true;
+
+ if (ClickMode == ClickMode.Release && new Rect(Bounds.Size).Contains(e.GetPosition(this)))
+ {
+ RaiseClickEvent();
+ }
}
}
@@ -275,7 +285,7 @@ namespace Avalonia.Controls
{
var button = e.Sender as Button;
var isDefault = (bool)e.NewValue;
- var inputRoot = button.VisualRoot as IInputElement;
+ var inputRoot = button?.VisualRoot as IInputElement;
if (inputRoot != null)
{
diff --git a/src/Avalonia.Controls/Classes.cs b/src/Avalonia.Controls/Classes.cs
index 02fd6e63bf..c897e86697 100644
--- a/src/Avalonia.Controls/Classes.cs
+++ b/src/Avalonia.Controls/Classes.cs
@@ -86,6 +86,20 @@ namespace Avalonia.Controls
base.AddRange(c);
}
+ ///
+ /// Remvoes all non-pseudoclasses from the collection.
+ ///
+ public override void Clear()
+ {
+ for (var i = Count - 1; i >= 0; --i)
+ {
+ if (!this[i].StartsWith(":"))
+ {
+ RemoveAt(i);
+ }
+ }
+ }
+
///
/// Inserts a style class into the collection.
///
diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs
index 0a69a5277f..fdb04f4ade 100644
--- a/src/Avalonia.Controls/ContextMenu.cs
+++ b/src/Avalonia.Controls/ContextMenu.cs
@@ -19,7 +19,7 @@ namespace Avalonia.Controls
{
ContextMenuProperty.Changed.Subscribe(ContextMenuChanged);
- MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick);
+ MenuItem.ClickEvent.AddClassHandler(x => x.OnContextMenuClick, handledEventsToo: true);
}
///
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index ef253a28e2..eca5967a58 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -17,7 +17,9 @@ using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Logging;
using Avalonia.LogicalTree;
+using Avalonia.Rendering;
using Avalonia.Styling;
+using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@@ -33,7 +35,7 @@ namespace Avalonia.Controls
/// - Implements to allow styling to work on the control.
/// - Implements to form part of a logical tree.
///
- public class Control : InputElement, IControl, INamed, ISetInheritanceParent, ISetLogicalParent, ISupportInitialize
+ public class Control : InputElement, IControl, INamed, ISetInheritanceParent, ISetLogicalParent, ISupportInitialize, IVisualBrushInitialize
{
///
/// Defines the property.
@@ -116,6 +118,7 @@ namespace Avalonia.Controls
public Control()
{
_nameScope = this as INameScope;
+ _isAttachedToLogicalTree = this is IStyleRoot;
}
///
@@ -352,21 +355,37 @@ namespace Avalonia.Controls
if (--_initCount == 0 && _isAttachedToLogicalTree)
{
- if (!_styled)
- {
- RegisterWithNameScope();
- ApplyStyling();
- _styled = true;
- }
+ InitializeStylesIfNeeded();
- if (!IsInitialized)
- {
- IsInitialized = true;
- Initialized?.Invoke(this, EventArgs.Empty);
- }
+ InitializeIfNeeded();
+ }
+ }
+
+ private void InitializeStylesIfNeeded(bool force = false)
+ {
+ if (_initCount == 0 && (!_styled || force))
+ {
+ RegisterWithNameScope();
+ ApplyStyling();
+ _styled = true;
+ }
+ }
+
+ private void InitializeIfNeeded()
+ {
+ if (_initCount == 0 && !IsInitialized)
+ {
+ IsInitialized = true;
+ Initialized?.Invoke(this, EventArgs.Empty);
}
}
+ ///
+ void ILogical.NotifyAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ this.OnAttachedToLogicalTreeCore(e);
+ }
+
///
void ILogical.NotifyDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
@@ -416,7 +435,7 @@ namespace Avalonia.Controls
if (_isAttachedToLogicalTree)
{
- var oldRoot = FindStyleRoot(old);
+ var oldRoot = FindStyleRoot(old) ?? this as IStyleRoot;
if (oldRoot == null)
{
@@ -434,7 +453,7 @@ namespace Avalonia.Controls
_parent = (IControl)parent;
- if (_parent is IStyleRoot || _parent?.IsAttachedToLogicalTree == true)
+ if (_parent is IStyleRoot || _parent?.IsAttachedToLogicalTree == true || this is IStyleRoot)
{
var newRoot = FindStyleRoot(this);
@@ -460,6 +479,38 @@ namespace Avalonia.Controls
InheritanceParent = parent;
}
+ ///
+ void IVisualBrushInitialize.EnsureInitialized()
+ {
+ if (VisualRoot == null)
+ {
+ if (!IsInitialized)
+ {
+ foreach (var i in this.GetSelfAndVisualDescendants())
+ {
+ var c = i as IControl;
+
+ if (c?.IsInitialized == false)
+ {
+ var init = c as ISupportInitialize;
+
+ if (init != null)
+ {
+ init.BeginInit();
+ init.EndInit();
+ }
+ }
+ }
+ }
+
+ if (!IsArrangeValid)
+ {
+ Measure(Size.Infinity);
+ Arrange(new Rect(DesiredSize));
+ }
+ }
+ }
+
///
/// Adds a pseudo-class to be set when a property is true.
///
@@ -539,11 +590,7 @@ namespace Avalonia.Controls
{
base.OnAttachedToVisualTreeCore(e);
- if (!IsInitialized)
- {
- IsInitialized = true;
- Initialized?.Invoke(this, EventArgs.Empty);
- }
+ InitializeIfNeeded();
}
///
@@ -611,7 +658,7 @@ namespace Avalonia.Controls
if (_focusAdorner != null)
{
- var adornerLayer = _focusAdorner.Parent as Panel;
+ var adornerLayer = (IPanel)_focusAdorner.Parent;
adornerLayer.Children.Remove(_focusAdorner);
_focusAdorner = null;
}
@@ -711,12 +758,7 @@ namespace Avalonia.Controls
{
_isAttachedToLogicalTree = true;
- if (_initCount == 0)
- {
- RegisterWithNameScope();
- ApplyStyling();
- _styled = true;
- }
+ InitializeStylesIfNeeded(true);
OnAttachedToLogicalTree(e);
}
diff --git a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
index 4688017187..179dccaf76 100644
--- a/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
+++ b/src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
@@ -4,6 +4,7 @@ using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Styling;
+using JetBrains.Annotations;
namespace Avalonia.Controls.Embedding
{
@@ -18,8 +19,11 @@ namespace Avalonia.Controls.Embedding
{
}
+ [CanBeNull]
public new IEmbeddableWindowImpl PlatformImpl => (IEmbeddableWindowImpl) base.PlatformImpl;
+ protected bool EnforceClientSize { get; set; } = true;
+
public void Prepare()
{
EnsureInitialized();
@@ -36,11 +40,12 @@ namespace Avalonia.Controls.Embedding
init.EndInit();
}
}
-
+
protected override Size MeasureOverride(Size availableSize)
{
- base.MeasureOverride(PlatformImpl.ClientSize);
- return PlatformImpl.ClientSize;
+ if (EnforceClientSize)
+ availableSize = PlatformImpl?.ClientSize ?? default(Size);
+ return base.MeasureOverride(availableSize);
}
private readonly NameScope _nameScope = new NameScope();
@@ -63,9 +68,6 @@ namespace Avalonia.Controls.Embedding
public void Unregister(string name) => _nameScope.Unregister(name);
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
- public void Dispose()
- {
- PlatformImpl.Dispose();
- }
+ public void Dispose() => PlatformImpl?.Dispose();
}
}
diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs
index 43c8fbcbb4..f6f11aa9ad 100644
--- a/src/Avalonia.Controls/Image.cs
+++ b/src/Avalonia.Controls/Image.cs
@@ -63,10 +63,10 @@ namespace Avalonia.Controls
Vector scale = Stretch.CalculateScaling(Bounds.Size, sourceSize);
Size scaledSize = sourceSize * scale;
Rect destRect = viewPort
- .CenterIn(new Rect(scaledSize))
+ .CenterRect(new Rect(scaledSize))
.Intersect(viewPort);
Rect sourceRect = new Rect(sourceSize)
- .CenterIn(new Rect(destRect.Size / scale));
+ .CenterRect(new Rect(destRect.Size / scale));
context.DrawImage(source, 1, sourceRect, destRect);
}
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index 5d12c9963f..aa209e0462 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -354,7 +354,7 @@ namespace Avalonia.Controls
}
var collection = sender as ICollection;
- PseudoClasses.Set(":empty", collection.Count == 0);
+ PseudoClasses.Set(":empty", collection == null || collection.Count == 0);
}
///
diff --git a/src/Avalonia.Controls/Menu.cs b/src/Avalonia.Controls/Menu.cs
index e919275d4f..994af9dab8 100644
--- a/src/Avalonia.Controls/Menu.cs
+++ b/src/Avalonia.Controls/Menu.cs
@@ -47,7 +47,7 @@ namespace Avalonia.Controls
static Menu()
{
ItemsPanelProperty.OverrideDefaultValue(typeof(Menu), DefaultPanel);
- MenuItem.ClickEvent.AddClassHandler
Action Closed { get; set; }
+
+ ///
+ /// Gets a mouse device associated with toplevel
+ ///
+ [CanBeNull]
+ IMouseDevice MouseDevice { get; }
}
}
diff --git a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs
index 84988e912f..4dc96a074d 100644
--- a/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs
+++ b/src/Avalonia.Controls/Platform/Surfaces/IFramebufferPlatformSurface.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
+using Avalonia.Platform;
namespace Avalonia.Controls.Platform.Surfaces
{
diff --git a/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs b/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs
deleted file mode 100644
index c9f8eabe97..0000000000
--- a/src/Avalonia.Controls/Platform/Surfaces/PixelFormat.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Avalonia.Controls.Platform.Surfaces
-{
- public enum PixelFormat
- {
- Rgb565,
- Rgba8888,
- Bgra8888
- }
-}
diff --git a/src/Avalonia.Controls/Presenters/ContentPresenter.cs b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
index 40fc2f302c..c1adff402a 100644
--- a/src/Avalonia.Controls/Presenters/ContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ContentPresenter.cs
@@ -8,6 +8,7 @@ using Avalonia.Controls.Templates;
using Avalonia.Layout;
using Avalonia.LogicalTree;
using Avalonia.Media;
+using Avalonia.VisualTree;
namespace Avalonia.Controls.Presenters
{
@@ -88,6 +89,7 @@ namespace Avalonia.Controls.Presenters
static ContentPresenter()
{
ContentProperty.Changed.AddClassHandler(x => x.ContentChanged);
+ ContentTemplateProperty.Changed.AddClassHandler(x => x.ContentChanged);
TemplatedParentProperty.Changed.AddClassHandler(x => x.TemplatedParentChanged);
}
@@ -313,27 +315,22 @@ namespace Avalonia.Controls.Presenters
if (content != null && newChild == null)
{
- // We have content and it isn't a control, so first try to recycle the existing
- // child control to display the new data by querying if the template that created
- // the child can recycle items and that it also matches the new data.
- if (oldChild != null &&
- _dataTemplate != null &&
- _dataTemplate.SupportsRecycling &&
- _dataTemplate.Match(content))
+ var dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? FuncDataTemplate.Default;
+
+ // We have content and it isn't a control, so if the new data template is the same
+ // as the old data template, try to recycle the existing child control to display
+ // the new data.
+ if (dataTemplate == _dataTemplate && dataTemplate.SupportsRecycling)
{
newChild = oldChild;
}
else
{
- // We couldn't recycle an existing control so find a data template for the data
- // and use it to create a control.
- _dataTemplate = this.FindDataTemplate(content, ContentTemplate) ?? FuncDataTemplate.Default;
+ _dataTemplate = dataTemplate;
newChild = _dataTemplate.Build(content);
- // Try to give the new control its own name scope.
- var controlResult = newChild as Control;
-
- if (controlResult != null)
+ // Give the new control its own name scope.
+ if (newChild is Control controlResult)
{
NameScope.SetNameScope(controlResult, new NameScope());
}
@@ -424,6 +421,19 @@ namespace Avalonia.Controls.Presenters
private void ContentChanged(AvaloniaPropertyChangedEventArgs e)
{
_createdChild = false;
+
+ if (((ILogical)this).IsAttachedToLogicalTree)
+ {
+ UpdateChild();
+ }
+ else if (Child != null)
+ {
+ VisualChildren.Remove(Child);
+ LogicalChildren.Remove(Child);
+ Child = null;
+ _dataTemplate = null;
+ }
+
InvalidateMeasure();
}
diff --git a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
index 96190720ae..20602d5475 100644
--- a/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
+++ b/src/Avalonia.Controls/Presenters/ItemVirtualizerSimple.cs
@@ -155,8 +155,7 @@ namespace Avalonia.Controls.Presenters
case NotifyCollectionChangedAction.Add:
CreateAndRemoveContainers();
- if (e.NewStartingIndex >= FirstIndex &&
- e.NewStartingIndex < NextIndex)
+ if (e.NewStartingIndex < NextIndex)
{
RecycleContainers();
}
diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
index d9f0260e39..e41c4e1e28 100644
--- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs
@@ -111,7 +111,7 @@ namespace Avalonia.Controls.Presenters
/// The target visual.
/// The portion of the target visual to bring into view.
/// True if the scroll offset was changed; otherwise false.
- public bool BringDescendentIntoView(IVisual target, Rect targetRect)
+ public bool BringDescendantIntoView(IVisual target, Rect targetRect)
{
if (Child == null)
{
@@ -133,7 +133,7 @@ namespace Avalonia.Controls.Presenters
return false;
}
- var rect = targetRect * transform.Value;
+ var rect = targetRect.TransformToAABB(transform.Value);
var offset = Offset;
var result = false;
@@ -262,7 +262,7 @@ namespace Avalonia.Controls.Presenters
private void BringIntoViewRequested(object sender, RequestBringIntoViewEventArgs e)
{
- e.Handled = BringDescendentIntoView(e.TargetObject, e.TargetRect);
+ e.Handled = BringDescendantIntoView(e.TargetObject, e.TargetRect);
}
private void ChildChanged(AvaloniaPropertyChangedEventArgs e)
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index 39759f78f1..a2b5f3f8b4 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -127,11 +127,11 @@ namespace Avalonia.Controls.Presenters
base.Render(context);
if (selectionStart == selectionEnd)
- {
+ {
var backgroundColor = (((Control)TemplatedParent).GetValue(BackgroundProperty) as SolidColorBrush)?.Color;
var caretBrush = Brushes.Black;
- if(backgroundColor.HasValue)
+ if (backgroundColor.HasValue)
{
byte red = (byte)~(backgroundColor.Value.R);
byte green = (byte)~(backgroundColor.Value.G);
@@ -139,7 +139,7 @@ namespace Avalonia.Controls.Presenters
caretBrush = new SolidColorBrush(Color.FromRgb(red, green, blue));
}
-
+
if (_caretBlink)
{
var charPos = FormattedText.HitTestTextPosition(CaretIndex);
@@ -212,7 +212,10 @@ namespace Avalonia.Controls.Presenters
if (length > 0)
{
- result.SetForegroundBrush(Brushes.White, start, length);
+ result.Spans = new[]
+ {
+ new FormattedTextStyleSpan(start, length, foregroundBrush: Brushes.White),
+ };
}
return result;
@@ -228,17 +231,13 @@ namespace Avalonia.Controls.Presenters
}
else
{
- // TODO: Pretty sure that measuring "X" isn't the right way to do this...
- using (var formattedText = new FormattedText(
- "X",
- FontFamily,
- FontSize,
- FontStyle,
- TextAlignment,
- FontWeight))
+ return new FormattedText
{
- return formattedText.Measure();
- }
+ Text = "X",
+ Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
+ TextAlignment = TextAlignment,
+ Constraint = availableSize,
+ }.Measure();
}
}
diff --git a/src/Avalonia.Controls/Primitives/AccessText.cs b/src/Avalonia.Controls/Primitives/AccessText.cs
index 42a6f9123b..4bb80e6d3f 100644
--- a/src/Avalonia.Controls/Primitives/AccessText.cs
+++ b/src/Avalonia.Controls/Primitives/AccessText.cs
@@ -85,15 +85,14 @@ namespace Avalonia.Controls.Primitives
/// A object.
protected override FormattedText CreateFormattedText(Size constraint)
{
- var result = new FormattedText(
- StripAccessKey(Text),
- FontFamily,
- FontSize,
- FontStyle,
- TextAlignment,
- FontWeight);
- result.Constraint = constraint;
- return result;
+ return new FormattedText
+ {
+ Constraint = constraint,
+ Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
+ Text = StripAccessKey(Text),
+ TextAlignment = TextAlignment,
+ Wrapping = TextWrapping,
+ };
}
///
diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs
index bb2a61c024..daea187a69 100644
--- a/src/Avalonia.Controls/Primitives/Popup.cs
+++ b/src/Avalonia.Controls/Primitives/Popup.cs
@@ -340,11 +340,11 @@ namespace Avalonia.Controls.Primitives
switch (mode)
{
case PlacementMode.Pointer:
- if (MouseDevice.Instance != null)
+ if(PopupRoot != null)
{
// Scales the Horizontal and Vertical offset to screen co-ordinates.
var screenOffset = new Point(HorizontalOffset * (PopupRoot as ILayoutRoot).LayoutScaling, VerticalOffset * (PopupRoot as ILayoutRoot).LayoutScaling);
- return MouseDevice.Instance.Position + screenOffset;
+ return (((IInputRoot)PopupRoot)?.MouseDevice?.Position ?? default(Point)) + screenOffset;
}
return default(Point);
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index 5e5177b29d..a999e4ae37 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -9,6 +9,7 @@ using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.VisualTree;
+using JetBrains.Annotations;
namespace Avalonia.Controls.Primitives
{
@@ -49,6 +50,7 @@ namespace Avalonia.Controls.Primitives
///
/// Gets the platform-specific window implementation.
///
+ [CanBeNull]
public new IPopupImpl PlatformImpl => (IPopupImpl)base.PlatformImpl;
///
@@ -65,37 +67,14 @@ namespace Avalonia.Controls.Primitives
IVisual IHostedVisualTreeRoot.Host => Parent;
///
- public void Dispose()
- {
- this.PlatformImpl.Dispose();
- }
-
- ///
- /// Hides the popup.
- ///
- public void Hide()
- {
- PlatformImpl.Hide();
- IsVisible = false;
- }
-
- ///
- /// Shows the popup.
- ///
- public void Show()
- {
- EnsureInitialized();
- PlatformImpl.Show();
- LayoutManager.Instance.ExecuteInitialLayoutPass(this);
- IsVisible = true;
- }
+ public void Dispose() => PlatformImpl?.Dispose();
///
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
- if (Parent.TemplatedParent != null)
+ if (Parent?.TemplatedParent != null)
{
if (_presenterSubscription != null)
{
@@ -109,16 +88,6 @@ namespace Avalonia.Controls.Primitives
}
}
- private void EnsureInitialized()
- {
- if (!this.IsInitialized)
- {
- var init = (ISupportInitialize)this;
- init.BeginInit();
- init.EndInit();
- }
- }
-
private void SetTemplatedParentAndApplyChildTemplates(IControl control)
{
var templatedParent = Parent.TemplatedParent;
diff --git a/src/Avalonia.Controls/Primitives/TemplatedControl.cs b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
index 7a42c48053..1ddfb97c14 100644
--- a/src/Avalonia.Controls/Primitives/TemplatedControl.cs
+++ b/src/Avalonia.Controls/Primitives/TemplatedControl.cs
@@ -285,6 +285,17 @@ namespace Avalonia.Controls.Primitives
return this;
}
+ ///
+ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ if (VisualChildren.Count > 0)
+ {
+ ((ILogical)VisualChildren[0]).NotifyAttachedToLogicalTree(e);
+ }
+
+ base.OnAttachedToLogicalTree(e);
+ }
+
///
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
diff --git a/src/Avalonia.Controls/Primitives/Thumb.cs b/src/Avalonia.Controls/Primitives/Thumb.cs
index 1fef48f55b..065b1aedbe 100644
--- a/src/Avalonia.Controls/Primitives/Thumb.cs
+++ b/src/Avalonia.Controls/Primitives/Thumb.cs
@@ -86,7 +86,7 @@ namespace Avalonia.Controls.Primitives
RaiseEvent(ev);
}
- protected override void OnPointerReleased(PointerEventArgs e)
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (_lastPoint.HasValue)
{
diff --git a/src/Avalonia.Controls/Templates/TemplateExtensions.cs b/src/Avalonia.Controls/Templates/TemplateExtensions.cs
index 535be23b23..09da737836 100644
--- a/src/Avalonia.Controls/Templates/TemplateExtensions.cs
+++ b/src/Avalonia.Controls/Templates/TemplateExtensions.cs
@@ -31,9 +31,9 @@ namespace Avalonia.Controls.Templates
if (child.TemplatedParent != null)
{
- foreach (var descendent in GetTemplateChildren(child, templatedParent))
+ foreach (var descendant in GetTemplateChildren(child, templatedParent))
{
- yield return descendent;
+ yield return descendant;
}
}
}
diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs
index 028df729a5..c7a77bdf0e 100644
--- a/src/Avalonia.Controls/TextBlock.cs
+++ b/src/Avalonia.Controls/TextBlock.cs
@@ -116,7 +116,7 @@ namespace Avalonia.Controls
this.GetObservable(TextAlignmentProperty).Select(_ => Unit.Default),
this.GetObservable(FontSizeProperty).Select(_ => Unit.Default),
this.GetObservable(FontStyleProperty).Select(_ => Unit.Default),
- this.GetObservable(FontWeightProperty).Select(_=>Unit.Default))
+ this.GetObservable(FontWeightProperty).Select(_ => Unit.Default))
.Subscribe(_ =>
{
InvalidateFormattedText();
@@ -350,16 +350,14 @@ namespace Avalonia.Controls
/// A object.
protected virtual FormattedText CreateFormattedText(Size constraint)
{
- var result = new FormattedText(
- Text ?? string.Empty,
- FontFamily,
- FontSize,
- FontStyle,
- TextAlignment,
- FontWeight,
- TextWrapping);
- result.Constraint = constraint;
- return result;
+ return new FormattedText
+ {
+ Constraint = constraint,
+ Typeface = new Typeface(FontFamily, FontSize, FontStyle, FontWeight),
+ Text = Text ?? string.Empty,
+ TextAlignment = TextAlignment,
+ Wrapping = TextWrapping,
+ };
}
///
@@ -370,7 +368,6 @@ namespace Avalonia.Controls
if (_formattedText != null)
{
_constraint = _formattedText.Constraint;
- _formattedText.Dispose();
_formattedText = null;
}
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 719e888dd4..92ab12f82e 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -236,6 +236,11 @@ namespace Avalonia.Controls
{
_presenter = e.NameScope.Get("PART_TextPresenter");
_presenter.Cursor = new Cursor(StandardCursorType.Ibeam);
+
+ if(IsFocused)
+ {
+ _presenter.ShowCaret();
+ }
}
protected override void OnGotFocus(GotFocusEventArgs e)
@@ -254,7 +259,7 @@ namespace Avalonia.Controls
}
else
{
- _presenter.ShowCaret();
+ _presenter?.ShowCaret();
}
}
@@ -263,7 +268,7 @@ namespace Avalonia.Controls
base.OnLostFocus(e);
SelectionStart = 0;
SelectionEnd = 0;
- _presenter.HideCaret();
+ _presenter?.HideCaret();
}
protected override void OnTextInput(TextInputEventArgs e)
@@ -522,7 +527,7 @@ namespace Avalonia.Controls
}
}
- protected override void OnPointerReleased(PointerEventArgs e)
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (_presenter != null && e.Device.Captured == _presenter)
{
@@ -720,7 +725,7 @@ namespace Avalonia.Controls
if (pos < text.Length)
{
--pos;
- if (pos > 0 && Text[pos - 1] == '\r' && Text[pos] == '\n')
+ if (pos > 0 && text[pos - 1] == '\r' && text[pos] == '\n')
{
--pos;
}
@@ -771,6 +776,9 @@ namespace Avalonia.Controls
private string GetSelection()
{
+ var text = Text;
+ if (string.IsNullOrEmpty(text))
+ return "";
var selectionStart = SelectionStart;
var selectionEnd = SelectionEnd;
var start = Math.Min(selectionStart, selectionEnd);
@@ -779,7 +787,7 @@ namespace Avalonia.Controls
{
return "";
}
- return Text.Substring(start, end - start);
+ return text.Substring(start, end - start);
}
private int GetLine(int caretIndex, IList lines)
diff --git a/src/Avalonia.Controls/ToolTip.cs b/src/Avalonia.Controls/ToolTip.cs
index cff3dab150..e1b69637af 100644
--- a/src/Avalonia.Controls/ToolTip.cs
+++ b/src/Avalonia.Controls/ToolTip.cs
@@ -105,21 +105,29 @@ namespace Avalonia.Controls
{
if (control != null && control.IsVisible && control.GetVisualRoot() != null)
{
- if (s_popup != null)
- {
- throw new AvaloniaInternalException("Previous ToolTip not disposed.");
- }
+ var cp = (control.GetVisualRoot() as IInputRoot)?.MouseDevice?.GetPosition(control);
- var cp = MouseDevice.Instance?.GetPosition(control);
- var position = control.PointToScreen(cp ?? new Point(0, 0)) + new Vector(0, 22);
+ if (cp.HasValue && control.IsVisible && new Rect(control.Bounds.Size).Contains(cp.Value))
+ {
+ var position = control.PointToScreen(cp.Value) + new Vector(0, 22);
+
+ if (s_popup == null)
+ {
+ s_popup = new PopupRoot();
+ s_popup.Content = new ToolTip();
+ }
+ else
+ {
+ ((ISetLogicalParent)s_popup).SetParent(null);
+ }
- s_popup = new PopupRoot();
((ISetLogicalParent)s_popup).SetParent(control);
- s_popup.Content = new ToolTip { Content = GetTip(control) };
- s_popup.Position = position;
- s_popup.Show();
+ ((ToolTip)s_popup.Content).Content = GetTip(control);
+ s_popup.Position = position;
+ s_popup.Show();
- s_current = control;
+ s_current = control;
+ }
}
}
@@ -147,16 +155,23 @@ namespace Avalonia.Controls
{
if (s_popup != null)
{
- // Clear the ToolTip's Content in case it has control content: this will
- // reset its visual parent allowing it to be used again.
- ((ToolTip)s_popup.Content).Content = null;
-
- // Dispose of the popup.
- s_popup.Dispose();
- s_popup = null;
+ DisposeTooltip();
+ s_show.OnNext(null);
}
+ }
+ }
+
+ private static void DisposeTooltip()
+ {
+ if (s_popup != null)
+ {
+ // Clear the ToolTip's Content in case it has control content: this will
+ // reset its visual parent allowing it to be used again.
+ ((ToolTip)s_popup.Content).Content = null;
- s_show.OnNext(null);
+ // Dispose of the popup.
+ s_popup.Dispose();
+ s_popup = null;
}
}
}
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index 4de0256a7d..f8db0e2a5b 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -14,6 +14,7 @@ using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Styling;
using Avalonia.VisualTree;
+using JetBrains.Annotations;
namespace Avalonia.Controls
{
@@ -89,28 +90,27 @@ namespace Avalonia.Controls
_renderInterface = TryGetService(dependencyResolver);
var renderLoop = TryGetService(dependencyResolver);
- var rendererFactory = TryGetService(dependencyResolver);
- Renderer = rendererFactory?.CreateRenderer(this, renderLoop);
+ Renderer = impl.CreateRenderer(this);
- PlatformImpl.SetInputRoot(this);
+ impl.SetInputRoot(this);
+
+ impl.Closed = HandleClosed;
+ impl.Input = HandleInput;
+ impl.Paint = HandlePaint;
+ impl.Resized = HandleResized;
+ impl.ScalingChanged = HandleScalingChanged;
- PlatformImpl.Closed = HandleClosed;
- PlatformImpl.Input = HandleInput;
- PlatformImpl.Paint = Renderer != null ? (Action)Renderer.Render : null;
- PlatformImpl.Resized = HandleResized;
- PlatformImpl.ScalingChanged = HandleScalingChanged;
-
_keyboardNavigationHandler?.SetOwner(this);
_accessKeyHandler?.SetOwner(this);
styler?.ApplyStyles(this);
- ClientSize = PlatformImpl.ClientSize;
+ ClientSize = impl.ClientSize;
this.GetObservable(PointerOverElementProperty)
.Select(
x => (x as InputElement)?.GetObservable(CursorProperty) ?? Observable.Empty())
- .Switch().Subscribe(cursor => PlatformImpl.SetCursor(cursor?.PlatformCursor));
+ .Switch().Subscribe(cursor => PlatformImpl?.SetCursor(cursor?.PlatformCursor));
if (_applicationLifecycle != null)
{
@@ -135,10 +135,8 @@ namespace Avalonia.Controls
///
/// Gets the platform-specific window implementation.
///
- public ITopLevelImpl PlatformImpl
- {
- get;
- }
+ [CanBeNull]
+ public ITopLevelImpl PlatformImpl { get; private set; }
///
/// Gets the renderer for the window.
@@ -164,6 +162,9 @@ namespace Avalonia.Controls
set { SetValue(PointerOverElementProperty, value); }
}
+ ///
+ IMouseDevice IInputRoot.MouseDevice => PlatformImpl?.MouseDevice;
+
///
/// Gets or sets a value indicating whether access keys are shown in the window.
///
@@ -177,37 +178,65 @@ namespace Avalonia.Controls
Size ILayoutRoot.MaxClientSize => Size.Infinity;
///
- double ILayoutRoot.LayoutScaling => PlatformImpl.Scaling;
+ double ILayoutRoot.LayoutScaling => PlatformImpl?.Scaling ?? 1;
+
+ ///
+ double IRenderRoot.RenderScaling => PlatformImpl?.Scaling ?? 1;
IStyleHost IStyleHost.StylingParent
{
get { return AvaloniaLocator.Current.GetService(); }
}
+ IRenderTarget IRenderRoot.CreateRenderTarget() => CreateRenderTarget();
+
///
- IRenderTarget IRenderRoot.CreateRenderTarget()
+ protected virtual IRenderTarget CreateRenderTarget()
{
+ if(PlatformImpl == null)
+ throw new InvalidOperationException("Cann't create render target, PlatformImpl is null (might be already disposed)");
return _renderInterface.CreateRenderTarget(PlatformImpl.Surfaces);
}
///
void IRenderRoot.Invalidate(Rect rect)
{
- PlatformImpl.Invalidate(rect);
+ PlatformImpl?.Invalidate(rect);
}
///
Point IRenderRoot.PointToClient(Point p)
{
- return PlatformImpl.PointToClient(p);
+ return PlatformImpl?.PointToClient(p) ?? default(Point);
}
///
Point IRenderRoot.PointToScreen(Point p)
{
- return PlatformImpl.PointToScreen(p);
+ return PlatformImpl?.PointToScreen(p) ?? default(Point);
}
+ ///
+ /// Handles a paint notification from .
+ ///
+ /// The dirty area.
+ protected virtual void HandlePaint(Rect rect)
+ {
+ Renderer?.Paint(rect);
+ }
+
+ ///
+ /// Handles a closed notification from .
+ ///
+ protected virtual void HandleClosed()
+ {
+ PlatformImpl = null;
+
+ Closed?.Invoke(this, EventArgs.Empty);
+ Renderer?.Dispose();
+ Renderer = null;
+ _applicationLifecycle.OnExit -= OnApplicationExiting;
+ }
///
/// Handles a resize notification from .
@@ -219,7 +248,7 @@ namespace Avalonia.Controls
Width = clientSize.Width;
Height = clientSize.Height;
LayoutManager.Instance.ExecuteLayoutPass();
- PlatformImpl.Invalidate(new Rect(clientSize));
+ Renderer?.Resized(clientSize);
}
///
@@ -229,7 +258,7 @@ namespace Avalonia.Controls
/// The window scaling.
protected virtual void HandleScalingChanged(double scaling)
{
- foreach (ILayoutable control in this.GetSelfAndVisualDescendents())
+ foreach (ILayoutable control in this.GetSelfAndVisualDescendants())
{
control.InvalidateMeasure();
}
@@ -267,17 +296,6 @@ namespace Avalonia.Controls
return result;
}
- ///
- /// Handles a closed notification from .
- ///
- private void HandleClosed()
- {
- Closed?.Invoke(this, EventArgs.Empty);
- Renderer?.Dispose();
- Renderer = null;
- _applicationLifecycle.OnExit -= OnApplicationExiting;
- }
-
private void OnApplicationExiting(object sender, EventArgs args)
{
HandleApplicationExiting();
diff --git a/src/Avalonia.Controls/TreeView.cs b/src/Avalonia.Controls/TreeView.cs
index b966d09b1f..5d1b9a1462 100644
--- a/src/Avalonia.Controls/TreeView.cs
+++ b/src/Avalonia.Controls/TreeView.cs
@@ -16,7 +16,7 @@ namespace Avalonia.Controls
///
/// Displays a hierachical tree of data.
///
- public class TreeView : ItemsControl
+ public class TreeView : ItemsControl, ICustomKeyboardNavigation
{
///
/// Defines the property.
@@ -90,6 +90,26 @@ namespace Avalonia.Controls
}
}
+ (bool handled, IInputElement next) ICustomKeyboardNavigation.GetNext(IInputElement element, NavigationDirection direction)
+ {
+ if (direction == NavigationDirection.Next || direction == NavigationDirection.Previous)
+ {
+ if (!this.IsVisualAncestorOf(element))
+ {
+ IControl result = _selectedItem != null ?
+ ItemContainerGenerator.Index.ContainerFromItem(_selectedItem) :
+ ItemContainerGenerator.ContainerFromIndex(0);
+ return (true, result);
+ }
+ else
+ {
+ return (true, null);
+ }
+ }
+
+ return (false, null);
+ }
+
///
protected override IItemContainerGenerator CreateItemContainerGenerator()
{
diff --git a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs
index 71ba3793d1..be4c1aa6c4 100644
--- a/src/Avalonia.Controls/Utils/UndoRedoHelper.cs
+++ b/src/Avalonia.Controls/Utils/UndoRedoHelper.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-using JetBrains.Annotations;
using Avalonia.Utilities;
namespace Avalonia.Controls.Utils
diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs
index 992279d981..46c625cc4c 100644
--- a/src/Avalonia.Controls/Window.cs
+++ b/src/Avalonia.Controls/Window.cs
@@ -11,6 +11,8 @@ using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Styling;
using System.Collections.Generic;
+using System.Linq;
+using JetBrains.Annotations;
namespace Avalonia.Controls
{
@@ -45,12 +47,12 @@ namespace Avalonia.Controls
///
public class Window : WindowBase, IStyleable, IFocusScope, ILayoutRoot, INameScope
{
- private static IList s_windows = new List();
+ private static List s_windows = new List();
///
/// Retrieves an enumeration of all Windows in the currently running application.
///
- public static IList OpenWindows => s_windows;
+ public static IReadOnlyList OpenWindows => s_windows;
///
/// Defines the property.
@@ -86,11 +88,11 @@ namespace Avalonia.Controls
static Window()
{
BackgroundProperty.OverrideDefaultValue(typeof(Window), Brushes.White);
- TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetTitle((string)e.NewValue));
+ TitleProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetTitle((string)e.NewValue));
HasSystemDecorationsProperty.Changed.AddClassHandler(
- (s, e) => s.PlatformImpl.SetSystemDecorations((bool) e.NewValue));
+ (s, e) => s.PlatformImpl?.SetSystemDecorations((bool) e.NewValue));
- IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
+ IconProperty.Changed.AddClassHandler((s, e) => s.PlatformImpl?.SetIcon(((WindowIcon)e.NewValue).PlatformImpl));
}
///
@@ -108,7 +110,7 @@ namespace Avalonia.Controls
public Window(IWindowImpl impl)
: base(impl)
{
- _maxPlatformClientSize = this.PlatformImpl.MaxClientSize;
+ _maxPlatformClientSize = PlatformImpl?.MaxClientSize ?? default(Size);
}
///
@@ -128,6 +130,7 @@ namespace Avalonia.Controls
///
/// Gets the platform-specific window implementation.
///
+ [CanBeNull]
public new IWindowImpl PlatformImpl => (IWindowImpl)base.PlatformImpl;
///
@@ -163,8 +166,12 @@ namespace Avalonia.Controls
///
public WindowState WindowState
{
- get { return this.PlatformImpl.WindowState; }
- set { this.PlatformImpl.WindowState = value; }
+ get { return PlatformImpl?.WindowState ?? WindowState.Normal; }
+ set
+ {
+ if (PlatformImpl != null)
+ PlatformImpl.WindowState = value;
+ }
}
///
@@ -188,7 +195,8 @@ namespace Avalonia.Controls
public void Close()
{
s_windows.Remove(this);
- PlatformImpl.Dispose();
+ PlatformImpl?.Dispose();
+ IsVisible = false;
}
protected override void HandleApplicationExiting()
@@ -215,27 +223,42 @@ namespace Avalonia.Controls
///
/// Hides the window but does not close it.
///
- public void Hide()
+ public override void Hide()
{
+ if (!IsVisible)
+ {
+ return;
+ }
+
using (BeginAutoSizing())
{
- PlatformImpl.Hide();
+ Renderer?.Stop();
+ PlatformImpl?.Hide();
}
+
+ IsVisible = false;
}
///
/// Shows the window.
///
- public void Show()
+ public override void Show()
{
+ if (IsVisible)
+ {
+ return;
+ }
+
s_windows.Add(this);
EnsureInitialized();
+ IsVisible = true;
LayoutManager.Instance.ExecuteInitialLayoutPass(this);
using (BeginAutoSizing())
{
- PlatformImpl.Show();
+ PlatformImpl?.Show();
+ Renderer?.Start();
}
}
@@ -261,21 +284,37 @@ namespace Avalonia.Controls
///
public Task ShowDialog()
{
+ if (IsVisible)
+ {
+ throw new InvalidOperationException("The window is already being shown.");
+ }
+
s_windows.Add(this);
EnsureInitialized();
+ IsVisible = true;
LayoutManager.Instance.ExecuteInitialLayoutPass(this);
using (BeginAutoSizing())
{
- var modal = PlatformImpl.ShowDialog();
+ var affectedWindows = s_windows.Where(w => w.IsEnabled && w != this).ToList();
+ var activated = affectedWindows.Where(w => w.IsActive).FirstOrDefault();
+ SetIsEnabled(affectedWindows, false);
+
+ var modal = PlatformImpl?.ShowDialog();
var result = new TaskCompletionSource();
- Observable.FromEventPattern(this, nameof(Closed))
+ Renderer?.Start();
+
+ Observable.FromEventPattern(
+ x => this.Closed += x,
+ x => this.Closed -= x)
.Take(1)
.Subscribe(_ =>
{
- modal.Dispose();
+ modal?.Dispose();
+ SetIsEnabled(affectedWindows, true);
+ activated?.Activate();
result.SetResult((TResult)_dialogResult);
});
@@ -283,6 +322,14 @@ namespace Avalonia.Controls
}
}
+ void SetIsEnabled(IEnumerable windows, bool isEnabled)
+ {
+ foreach (var window in windows)
+ {
+ window.IsEnabled = isEnabled;
+ }
+ }
+
///
void INameScope.Register(string name, object element)
{
@@ -329,6 +376,13 @@ namespace Avalonia.Controls
return size;
}
+ protected override void HandleClosed()
+ {
+ IsVisible = false;
+ s_windows.Remove(this);
+ base.HandleClosed();
+ }
+
///
protected override void HandleResized(Size clientSize)
{
@@ -339,16 +393,6 @@ namespace Avalonia.Controls
base.HandleResized(clientSize);
}
-
- private void EnsureInitialized()
- {
- if (!this.IsInitialized)
- {
- var init = (ISupportInitialize)this;
- init.BeginInit();
- init.EndInit();
- }
- }
}
}
diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs
index ac6eea8641..bcc09936ba 100644
--- a/src/Avalonia.Controls/WindowBase.cs
+++ b/src/Avalonia.Controls/WindowBase.cs
@@ -9,6 +9,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
+using JetBrains.Annotations;
namespace Avalonia.Controls
{
@@ -28,7 +29,15 @@ namespace Avalonia.Controls
public static readonly DirectProperty IsActiveProperty =
AvaloniaProperty.RegisterDirect(nameof(IsActive), o => o.IsActive);
+ private bool _hasExecutedInitialLayoutPass;
private bool _isActive;
+ private bool _ignoreVisibilityChange;
+
+ static WindowBase()
+ {
+ IsVisibleProperty.OverrideDefaultValue(false);
+ IsVisibleProperty.Changed.AddClassHandler(x => x.IsVisibleChanged);
+ }
public WindowBase(IWindowBaseImpl impl) : this(impl, AvaloniaLocator.Current)
{
@@ -36,10 +45,10 @@ namespace Avalonia.Controls
public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver)
{
- PlatformImpl.Activated = HandleActivated;
- PlatformImpl.Deactivated = HandleDeactivated;
- PlatformImpl.PositionChanged = HandlePositionChanged;
- this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl.Resize(x));
+ impl.Activated = HandleActivated;
+ impl.Deactivated = HandleDeactivated;
+ impl.PositionChanged = HandlePositionChanged;
+ this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x));
}
///
@@ -57,9 +66,9 @@ namespace Avalonia.Controls
///
public event EventHandler PositionChanged;
+ [CanBeNull]
public new IWindowBaseImpl PlatformImpl => (IWindowBaseImpl) base.PlatformImpl;
-
///
/// Gets a value that indicates whether the window is active.
///
@@ -74,8 +83,12 @@ namespace Avalonia.Controls
///
public Point Position
{
- get { return PlatformImpl.Position; }
- set { PlatformImpl.Position = value; }
+ get { return PlatformImpl?.Position ?? default(Point); }
+ set
+ {
+ if (PlatformImpl is IWindowBaseImpl impl)
+ impl.Position = value;
+ }
}
///
@@ -92,9 +105,54 @@ namespace Avalonia.Controls
///
public void Activate()
{
- PlatformImpl.Activate();
+ PlatformImpl?.Activate();
+ }
+
+ ///
+ /// Hides the popup.
+ ///
+ public virtual void Hide()
+ {
+ _ignoreVisibilityChange = true;
+
+ try
+ {
+ Renderer?.Stop();
+ PlatformImpl?.Hide();
+ IsVisible = false;
+ }
+ finally
+ {
+ _ignoreVisibilityChange = false;
+ }
}
+ ///
+ /// Shows the popup.
+ ///
+ public virtual void Show()
+ {
+ _ignoreVisibilityChange = true;
+
+ try
+ {
+ EnsureInitialized();
+ IsVisible = true;
+
+ if (!_hasExecutedInitialLayoutPass)
+ {
+ LayoutManager.Instance.ExecuteInitialLayoutPass(this);
+ _hasExecutedInitialLayoutPass = true;
+ }
+
+ PlatformImpl?.Show();
+ Renderer?.Start();
+ }
+ finally
+ {
+ _ignoreVisibilityChange = false;
+ }
+ }
///
/// Begins an auto-resize operation.
@@ -120,10 +178,38 @@ namespace Avalonia.Controls
{
using (BeginAutoSizing())
{
- PlatformImpl.Resize(finalSize);
+ PlatformImpl?.Resize(finalSize);
+ }
+
+ return base.ArrangeOverride(PlatformImpl?.ClientSize ?? default(Size));
+ }
+
+ ///
+ /// Ensures that the window is initialized.
+ ///
+ protected void EnsureInitialized()
+ {
+ if (!IsInitialized)
+ {
+ var init = (ISupportInitialize)this;
+ init.BeginInit();
+ init.EndInit();
}
+ }
- return base.ArrangeOverride(PlatformImpl.ClientSize);
+ protected override void HandleClosed()
+ {
+ _ignoreVisibilityChange = true;
+
+ try
+ {
+ IsVisible = false;
+ base.HandleClosed();
+ }
+ finally
+ {
+ _ignoreVisibilityChange = false;
+ }
}
///
@@ -139,8 +225,7 @@ namespace Avalonia.Controls
}
ClientSize = clientSize;
LayoutManager.Instance.ExecuteLayoutPass();
- PlatformImpl.Invalidate(new Rect(clientSize));
-
+ Renderer?.Resized(clientSize);
}
///
@@ -180,15 +265,30 @@ namespace Avalonia.Controls
Deactivated?.Invoke(this, EventArgs.Empty);
}
+ private void IsVisibleChanged(AvaloniaPropertyChangedEventArgs e)
+ {
+ if (!_ignoreVisibilityChange)
+ {
+ if ((bool)e.NewValue)
+ {
+ Show();
+ }
+ else
+ {
+ Hide();
+ }
+ }
+ }
+
///
/// Starts moving a window with left button being held. Should be called from left mouse button press event handler
///
- public void BeginMoveDrag() => PlatformImpl.BeginMoveDrag();
+ public void BeginMoveDrag() => PlatformImpl?.BeginMoveDrag();
///
/// Starts resizing a window. This function is used if an application has window resizing controls.
/// Should be called from left mouse button press event handler
///
- public void BeginResizeDrag(WindowEdge edge) => PlatformImpl.BeginResizeDrag(edge);
+ public void BeginResizeDrag(WindowEdge edge) => PlatformImpl?.BeginResizeDrag(edge);
}
}
diff --git a/src/Avalonia.Controls/packages.config b/src/Avalonia.Controls/packages.config
deleted file mode 100644
index c372c92f3f..0000000000
--- a/src/Avalonia.Controls/packages.config
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
index d9174d6f36..a68e8760f2 100644
--- a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
+++ b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {799A7BB5-3C2C-48B6-85A7-406A12C420DA}
- Library
- Properties
- Avalonia
- Avalonia.DesignerSupport
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -40,87 +25,23 @@
CS1591
-
-
- {3e53a01a-b331-47f3-b828-4a5717e77a24}
- Avalonia.Markup.Xaml
-
-
- {6417e941-21bc-467b-a771-0de389353ce6}
- Avalonia.Markup
-
-
- {d211e587-d8bc-45b9-95a4-f297c8fa5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {D2221C82-4A25-4583-9B43-D791E3F6820C}
- Avalonia.Controls
-
-
- {62024B2D-53EB-4638-B26B-85EEAA54866E}
- Avalonia.Input
-
-
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Avalonia.Interactivity
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
-
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}
- Avalonia.Styling
-
-
- {3E10A5FA-E8DA-48B1-AD44-6A5B6CB7750F}
- Avalonia.Themes.Default
-
+
+
+
+
+
+
+
+
+
+
+
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
+
+
\ No newline at end of file
diff --git a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.v2.ncrunchproject b/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.DesignerSupport/Avalonia.DesignerSupport.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.DesignerSupport/DesignerAssist.cs b/src/Avalonia.DesignerSupport/DesignerAssist.cs
index c9ae89354c..2f5fc79147 100644
--- a/src/Avalonia.DesignerSupport/DesignerAssist.cs
+++ b/src/Avalonia.DesignerSupport/DesignerAssist.cs
@@ -5,8 +5,6 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
-using OmniXaml;
-using OmniXaml.ObjectAssembler;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Markup.Xaml;
@@ -75,7 +73,7 @@ namespace Avalonia.DesignerSupport
private static void SetScalingFactor(double factor)
{
PlatformManager.SetDesignerScalingFactor(factor);
- s_currentWindow?.PlatformImpl.Resize(s_currentWindow.ClientSize);
+ s_currentWindow?.PlatformImpl?.Resize(s_currentWindow.ClientSize);
}
static Window s_currentWindow;
@@ -149,6 +147,8 @@ namespace Avalonia.DesignerSupport
s_currentWindow = window;
window.Show();
Design.ApplyDesignerProperties(window, control);
+ // ReSharper disable once PossibleNullReferenceException
+ // Always not null at this point
Api.OnWindowCreated?.Invoke(window.PlatformImpl.Handle.Handle);
Api.OnResize?.Invoke();
}
diff --git a/src/Avalonia.DesignerSupport/packages.config b/src/Avalonia.DesignerSupport/packages.config
deleted file mode 100644
index 9f732f1bcb..0000000000
--- a/src/Avalonia.DesignerSupport/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
index a56575dab7..be3f397283 100644
--- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
+++ b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {7062AE20-5DCC-4442-9645-8195BDECE63E}
- Library
- Properties
- Avalonia.Diagnostics
- Avalonia.Diagnostics
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -41,117 +26,29 @@
true
-
-
- {3e53a01a-b331-47f3-b828-4a5717e77a24}
- Avalonia.Markup.Xaml
-
-
- {6417e941-21bc-467b-a771-0de389353ce6}
- Avalonia.Markup
-
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {D2221C82-4A25-4583-9B43-D791E3F6820C}
- Avalonia.Controls
-
-
- {62024B2D-53EB-4638-B26B-85EEAA54866E}
- Avalonia.Input
-
-
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Avalonia.Interactivity
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {6417B24E-49C2-4985-8DB2-3AB9D898EC91}
- Avalonia.ReactiveUI
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
-
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}
- Avalonia.Styling
-
-
- {3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}
- Avalonia.Themes.Default
-
+
+
+
+
+
+
+
+
+
+
+
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
- TreePageView.xaml
+
+ %(Filename)
-
- DevTools.xaml
-
-
-
-
-
-
- ..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
-
- Designer
-
-
+
Designer
-
-
+
+
\ No newline at end of file
diff --git a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.v2.ncrunchproject b/src/Avalonia.Diagnostics/Avalonia.Diagnostics.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Diagnostics/Avalonia.Diagnostics.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Diagnostics/DevTools.xaml.cs b/src/Avalonia.Diagnostics/DevTools.xaml.cs
index 5be252c5c3..6593a8cd42 100644
--- a/src/Avalonia.Diagnostics/DevTools.xaml.cs
+++ b/src/Avalonia.Diagnostics/DevTools.xaml.cs
@@ -11,15 +11,14 @@ using Avalonia.Input.Raw;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using Avalonia.VisualTree;
-using ReactiveUI;
namespace Avalonia
{
- public static class WindowExtensions
+ public static class DevToolsExtensions
{
- public static void AttachDevTools(this Window window)
+ public static void AttachDevTools(this TopLevel control)
{
- Avalonia.Diagnostics.DevTools.Attach(window);
+ Avalonia.Diagnostics.DevTools.Attach(control);
}
}
}
@@ -28,7 +27,7 @@ namespace Avalonia.Diagnostics
{
public class DevTools : UserControl
{
- private static Dictionary s_open = new Dictionary();
+ private static Dictionary s_open = new Dictionary();
private IDisposable _keySubscription;
public DevTools(IControl root)
@@ -44,9 +43,9 @@ namespace Avalonia.Diagnostics
public IControl Root { get; }
- public static IDisposable Attach(Window window)
+ public static IDisposable Attach(TopLevel control)
{
- return window.AddHandler(
+ return control.AddHandler(
KeyDownEvent,
WindowPreviewKeyDown,
RoutingStrategies.Tunnel);
@@ -56,16 +55,16 @@ namespace Avalonia.Diagnostics
{
if (e.Key == Key.F12)
{
- var window = (Window)sender;
+ var control = (TopLevel)sender;
var devToolsWindow = default(Window);
- if (s_open.TryGetValue(window, out devToolsWindow))
+ if (s_open.TryGetValue(control, out devToolsWindow))
{
devToolsWindow.Activate();
}
else
{
- var devTools = new DevTools(window);
+ var devTools = new DevTools(control);
devToolsWindow = new Window
{
@@ -74,12 +73,12 @@ namespace Avalonia.Diagnostics
Content = devTools,
DataTemplates = new DataTemplates
{
- new ViewLocator(),
+ new ViewLocator(),
}
};
devToolsWindow.Closed += devTools.DevToolsClosed;
- s_open.Add((Window)sender, devToolsWindow);
+ s_open.Add(control, devToolsWindow);
devToolsWindow.Show();
}
}
@@ -89,9 +88,7 @@ namespace Avalonia.Diagnostics
{
var devToolsWindow = (Window)sender;
var devTools = (DevTools)devToolsWindow.Content;
- var window = (Window)devTools.Root;
-
- s_open.Remove(window);
+ s_open.Remove((TopLevel)devTools.Root);
_keySubscription.Dispose();
devToolsWindow.Closed -= DevToolsClosed;
}
@@ -107,7 +104,8 @@ namespace Avalonia.Diagnostics
if ((e.Modifiers) == modifiers)
{
- var point = MouseDevice.Instance.GetPosition(Root);
+
+ var point = (Root.VisualRoot as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default(Point);
var control = Root.GetVisualsAt(point, x => (!(x is AdornerLayer) && x.IsVisible))
.FirstOrDefault();
diff --git a/src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs
index 34cc32972c..d723890196 100644
--- a/src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/ControlDetailsViewModel.cs
@@ -3,19 +3,18 @@
using System.Collections.Generic;
using System.Linq;
-using Avalonia.Controls;
-using ReactiveUI;
+using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
{
- internal class ControlDetailsViewModel : ReactiveObject
+ internal class ControlDetailsViewModel : ViewModelBase
{
- public ControlDetailsViewModel(Control control)
+ public ControlDetailsViewModel(IVisual control)
{
- if (control != null)
+ if (control is AvaloniaObject avaloniaObject)
{
- Properties = AvaloniaPropertyRegistry.Instance.GetRegistered(control)
- .Select(x => new PropertyDetails(control, x))
+ Properties = AvaloniaPropertyRegistry.Instance.GetRegistered(avaloniaObject)
+ .Select(x => new PropertyDetails(avaloniaObject, x))
.OrderBy(x => x.IsAttached)
.ThenBy(x => x.Name);
}
diff --git a/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs b/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
index dbee9ad624..2d3f978462 100644
--- a/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/DevToolsViewModel.cs
@@ -5,32 +5,50 @@ using System;
using System.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.Input;
-using ReactiveUI;
namespace Avalonia.Diagnostics.ViewModels
{
- internal class DevToolsViewModel : ReactiveObject
+ internal class DevToolsViewModel : ViewModelBase
{
- private ReactiveObject _content;
-
+ private ViewModelBase _content;
private int _selectedTab;
-
private TreePageViewModel _logicalTree;
-
private TreePageViewModel _visualTree;
-
- private readonly ObservableAsPropertyHelper _focusedControl;
-
- private readonly ObservableAsPropertyHelper _pointerOverElement;
+ private string _focusedControl;
+ private string _pointerOverElement;
public DevToolsViewModel(IControl root)
{
_logicalTree = new TreePageViewModel(LogicalTreeNode.Create(root));
_visualTree = new TreePageViewModel(VisualTreeNode.Create(root));
- this.WhenAnyValue(x => x.SelectedTab).Subscribe(index =>
+ UpdateFocusedControl();
+ KeyboardDevice.Instance.PropertyChanged += (s, e) =>
{
- switch (index)
+ if (e.PropertyName == nameof(KeyboardDevice.Instance.FocusedElement))
+ {
+ UpdateFocusedControl();
+ }
+ };
+
+ root.GetObservable(TopLevel.PointerOverElementProperty)
+ .Subscribe(x => PointerOverElement = x?.GetType().Name);
+ }
+
+ public ViewModelBase Content
+ {
+ get { return _content; }
+ private set { RaiseAndSetIfChanged(ref _content, value); }
+ }
+
+ public int SelectedTab
+ {
+ get { return _selectedTab; }
+ set
+ {
+ _selectedTab = value;
+
+ switch (value)
{
case 0:
Content = _logicalTree;
@@ -39,34 +57,23 @@ namespace Avalonia.Diagnostics.ViewModels
Content = _visualTree;
break;
}
- });
- _focusedControl = KeyboardDevice.Instance
- .WhenAnyValue(x => x.FocusedElement)
- .Select(x => x?.GetType().Name)
- .ToProperty(this, x => x.FocusedControl);
-
- _pointerOverElement = root.GetObservable(TopLevel.PointerOverElementProperty)
- .Select(x => x?.GetType().Name)
- .ToProperty(this, x => x.PointerOverElement);
+ RaisePropertyChanged();
+ }
}
- public ReactiveObject Content
+ public string FocusedControl
{
- get { return _content; }
- private set { this.RaiseAndSetIfChanged(ref _content, value); }
+ get { return _focusedControl; }
+ private set { RaiseAndSetIfChanged(ref _focusedControl, value); }
}
- public int SelectedTab
+ public string PointerOverElement
{
- get { return _selectedTab; }
- set { this.RaiseAndSetIfChanged(ref _selectedTab, value); }
+ get { return _pointerOverElement; }
+ private set { RaiseAndSetIfChanged(ref _pointerOverElement, value); }
}
- public string FocusedControl => _focusedControl.Value;
-
- public string PointerOverElement => _pointerOverElement.Value;
-
public void SelectControl(IControl control)
{
var tree = Content as TreePageViewModel;
@@ -76,5 +83,10 @@ namespace Avalonia.Diagnostics.ViewModels
tree.SelectControl(control);
}
}
+
+ private void UpdateFocusedControl()
+ {
+ _focusedControl = KeyboardDevice.Instance.FocusedElement?.GetType().Name;
+ }
}
}
diff --git a/src/Avalonia.Diagnostics/ViewModels/LogicalTreeNode.cs b/src/Avalonia.Diagnostics/ViewModels/LogicalTreeNode.cs
index dcb4e79402..e8a8951f0d 100644
--- a/src/Avalonia.Diagnostics/ViewModels/LogicalTreeNode.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/LogicalTreeNode.cs
@@ -2,9 +2,9 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.LogicalTree;
-using ReactiveUI;
namespace Avalonia.Diagnostics.ViewModels
{
@@ -13,7 +13,7 @@ namespace Avalonia.Diagnostics.ViewModels
public LogicalTreeNode(ILogical logical, TreeNode parent)
: base((Control)logical, parent)
{
- Children = logical.LogicalChildren.CreateDerivedCollection(x => new LogicalTreeNode(x, this));
+ Children = logical.LogicalChildren.CreateDerivedList(x => new LogicalTreeNode(x, this));
}
public static LogicalTreeNode[] Create(object control)
diff --git a/src/Avalonia.Diagnostics/ViewModels/PropertyDetails.cs b/src/Avalonia.Diagnostics/ViewModels/PropertyDetails.cs
index c06f2415cf..2609b74ce0 100644
--- a/src/Avalonia.Diagnostics/ViewModels/PropertyDetails.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/PropertyDetails.cs
@@ -3,16 +3,13 @@
using System;
using Avalonia.Data;
-using ReactiveUI;
namespace Avalonia.Diagnostics.ViewModels
{
- internal class PropertyDetails : ReactiveObject
+ internal class PropertyDetails : ViewModelBase
{
private object _value;
-
private string _priority;
-
private string _diagnostic;
public PropertyDetails(AvaloniaObject o, AvaloniaProperty property)
@@ -41,19 +38,19 @@ namespace Avalonia.Diagnostics.ViewModels
public string Priority
{
get { return _priority; }
- private set { this.RaiseAndSetIfChanged(ref _priority, value); }
+ private set { RaiseAndSetIfChanged(ref _priority, value); }
}
public string Diagnostic
{
get { return _diagnostic; }
- private set { this.RaiseAndSetIfChanged(ref _diagnostic, value); }
+ private set { RaiseAndSetIfChanged(ref _diagnostic, value); }
}
public object Value
{
get { return _value; }
- private set { this.RaiseAndSetIfChanged(ref _value, value); }
+ private set { RaiseAndSetIfChanged(ref _value, value); }
}
}
}
diff --git a/src/Avalonia.Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/ViewModels/TreeNode.cs
index f186304f7b..7c403e1b04 100644
--- a/src/Avalonia.Diagnostics/ViewModels/TreeNode.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/TreeNode.cs
@@ -5,46 +5,49 @@ using System;
using System.Collections.Specialized;
using System.Reactive;
using System.Reactive.Linq;
-using Avalonia.Controls;
+using Avalonia.Collections;
using Avalonia.Styling;
-using ReactiveUI;
+using Avalonia.VisualTree;
namespace Avalonia.Diagnostics.ViewModels
{
- internal class TreeNode : ReactiveObject
+ internal class TreeNode : ViewModelBase
{
private string _classes;
private bool _isExpanded;
- public TreeNode(Control control, TreeNode parent)
+ public TreeNode(IVisual visual, TreeNode parent)
{
- Control = control;
Parent = parent;
- Type = control.GetType().Name;
+ Type = visual.GetType().Name;
+ Visual = visual;
- var classesChanged = Observable.FromEventPattern<
- NotifyCollectionChangedEventHandler,
- NotifyCollectionChangedEventArgs>(
- x => control.Classes.CollectionChanged += x,
- x => control.Classes.CollectionChanged -= x)
- .TakeUntil(((IStyleable)control).StyleDetach);
+ if (visual is IStyleable styleable)
+ {
+ var classesChanged = Observable.FromEventPattern<
+ NotifyCollectionChangedEventHandler,
+ NotifyCollectionChangedEventArgs>(
+ x => styleable.Classes.CollectionChanged += x,
+ x => styleable.Classes.CollectionChanged -= x)
+ .TakeUntil(((IStyleable)styleable).StyleDetach);
- classesChanged.Select(_ => Unit.Default)
- .StartWith(Unit.Default)
- .Subscribe(_ =>
- {
- if (control.Classes.Count > 0)
+ classesChanged.Select(_ => Unit.Default)
+ .StartWith(Unit.Default)
+ .Subscribe(_ =>
{
- Classes = "(" + string.Join(" ", control.Classes) + ")";
- }
- else
- {
- Classes = string.Empty;
- }
- });
+ if (styleable.Classes.Count > 0)
+ {
+ Classes = "(" + string.Join(" ", styleable.Classes) + ")";
+ }
+ else
+ {
+ Classes = string.Empty;
+ }
+ });
+ }
}
- public IReadOnlyReactiveList Children
+ public IAvaloniaReadOnlyList Children
{
get;
protected set;
@@ -53,10 +56,10 @@ namespace Avalonia.Diagnostics.ViewModels
public string Classes
{
get { return _classes; }
- private set { this.RaiseAndSetIfChanged(ref _classes, value); }
+ private set { RaiseAndSetIfChanged(ref _classes, value); }
}
- public Control Control
+ public IVisual Visual
{
get;
}
@@ -64,7 +67,7 @@ namespace Avalonia.Diagnostics.ViewModels
public bool IsExpanded
{
get { return _isExpanded; }
- set { this.RaiseAndSetIfChanged(ref _isExpanded, value); }
+ set { RaiseAndSetIfChanged(ref _isExpanded, value); }
}
public TreeNode Parent
diff --git a/src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs b/src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs
index 92be04a056..dba44c5d0c 100644
--- a/src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/TreePageViewModel.cs
@@ -1,25 +1,19 @@
// 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.Reactive.Linq;
using Avalonia.Controls;
using Avalonia.VisualTree;
-using ReactiveUI;
namespace Avalonia.Diagnostics.ViewModels
{
- internal class TreePageViewModel : ReactiveObject
+ internal class TreePageViewModel : ViewModelBase
{
private TreeNode _selected;
-
- private readonly ObservableAsPropertyHelper _details;
+ private ControlDetailsViewModel _details;
public TreePageViewModel(TreeNode[] nodes)
{
Nodes = nodes;
- _details = this.WhenAnyValue(x => x.SelectedNode)
- .Select(x => x != null ? new ControlDetailsViewModel(x.Control) : null)
- .ToProperty(this, x => x.Details);
}
public TreeNode[] Nodes { get; protected set; }
@@ -27,10 +21,20 @@ namespace Avalonia.Diagnostics.ViewModels
public TreeNode SelectedNode
{
get { return _selected; }
- set { this.RaiseAndSetIfChanged(ref _selected, value); }
+ set
+ {
+ if (RaiseAndSetIfChanged(ref _selected, value))
+ {
+ Details = value != null ? new ControlDetailsViewModel(value.Visual) : null;
+ }
+ }
}
- public ControlDetailsViewModel Details => _details.Value;
+ public ControlDetailsViewModel Details
+ {
+ get { return _details; }
+ private set { RaiseAndSetIfChanged(ref _details, value); }
+ }
public TreeNode FindNode(IControl control)
{
@@ -79,7 +83,7 @@ namespace Avalonia.Diagnostics.ViewModels
private TreeNode FindNode(TreeNode node, IControl control)
{
- if (node.Control == control)
+ if (node.Visual == control)
{
return node;
}
diff --git a/src/Avalonia.Diagnostics/ViewModels/ViewModelBase.cs b/src/Avalonia.Diagnostics/ViewModels/ViewModelBase.cs
new file mode 100644
index 0000000000..349404603a
--- /dev/null
+++ b/src/Avalonia.Diagnostics/ViewModels/ViewModelBase.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using JetBrains.Annotations;
+
+namespace Avalonia.Diagnostics.ViewModels
+{
+ public class ViewModelBase : INotifyPropertyChanged
+ {
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ [NotifyPropertyChangedInvocator]
+ protected bool RaiseAndSetIfChanged(ref T field, T value, [CallerMemberName] string propertyName = null)
+ {
+ if (!EqualityComparer.Default.Equals(field, value))
+ {
+ field = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ return true;
+ }
+
+ return false;
+ }
+
+ [NotifyPropertyChangedInvocator]
+ protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ }
+}
diff --git a/src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs b/src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs
index d155572c14..8c070261d9 100644
--- a/src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs
+++ b/src/Avalonia.Diagnostics/ViewModels/VisualTreeNode.cs
@@ -1,31 +1,31 @@
// 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 Avalonia.Controls;
+using Avalonia.Collections;
+using Avalonia.Styling;
using Avalonia.VisualTree;
-using ReactiveUI;
namespace Avalonia.Diagnostics.ViewModels
{
internal class VisualTreeNode : TreeNode
{
public VisualTreeNode(IVisual visual, TreeNode parent)
- : base((Control)visual, parent)
+ : base(visual, parent)
{
var host = visual as IVisualTreeHost;
if (host?.Root == null)
{
- Children = visual.VisualChildren.CreateDerivedCollection(x => new VisualTreeNode(x, this));
+ Children = visual.VisualChildren.CreateDerivedList(x => new VisualTreeNode(x, this));
}
else
{
- Children = new ReactiveList(new[] { new VisualTreeNode(host.Root, this) });
+ Children = new AvaloniaList(new[] { new VisualTreeNode(host.Root, this) });
}
- if (Control != null)
+ if ((Visual is IStyleable styleable))
{
- IsInTemplate = Control.TemplatedParent != null;
+ IsInTemplate = styleable.TemplatedParent != null;
}
}
diff --git a/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs b/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
index 7cb74ebb33..d7bd6fd128 100644
--- a/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
+++ b/src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
@@ -8,7 +8,6 @@ using Avalonia.Controls;
using Avalonia.Diagnostics.ViewModels;
using Avalonia.Media;
using Avalonia.Styling;
-using ReactiveUI;
namespace Avalonia.Diagnostics.Views
{
@@ -16,6 +15,7 @@ namespace Avalonia.Diagnostics.Views
{
private static readonly StyledProperty ViewModelProperty =
AvaloniaProperty.Register("ViewModel");
+ private SimpleGrid _grid;
public ControlDetailsView()
{
@@ -27,7 +27,11 @@ namespace Avalonia.Diagnostics.Views
public ControlDetailsViewModel ViewModel
{
get { return GetValue(ViewModelProperty); }
- private set { SetValue(ViewModelProperty, value); }
+ private set
+ {
+ SetValue(ViewModelProperty, value);
+ _grid[GridRepeater.ItemsProperty] = value?.Properties;
+ }
}
private void InitializeComponent()
@@ -36,7 +40,7 @@ namespace Avalonia.Diagnostics.Views
Content = new ScrollViewer
{
- Content = new SimpleGrid
+ Content = _grid = new SimpleGrid
{
Styles = new Styles
{
@@ -49,7 +53,6 @@ namespace Avalonia.Diagnostics.Views
},
},
[GridRepeater.TemplateProperty] = pt,
- [!GridRepeater.ItemsProperty] = this.WhenAnyValue(x => x.ViewModel.Properties).ToBinding(),
}
};
}
@@ -62,16 +65,13 @@ namespace Avalonia.Diagnostics.Views
{
Text = property.Name,
TextWrapping = TextWrapping.NoWrap,
- [!ToolTip.TipProperty] = property
- .WhenAnyValue(x => x.Diagnostic)
- .ToBinding(),
+ [!ToolTip.TipProperty] = property.GetObservable(nameof(property.Diagnostic)).ToBinding(),
};
yield return new TextBlock
{
TextWrapping = TextWrapping.NoWrap,
- [!TextBlock.TextProperty] = property
- .WhenAnyValue(v => v.Value)
+ [!TextBlock.TextProperty] = property.GetObservable(nameof(property.Value))
.Select(v => v?.ToString())
.ToBinding(),
};
@@ -79,7 +79,7 @@ namespace Avalonia.Diagnostics.Views
yield return new TextBlock
{
TextWrapping = TextWrapping.NoWrap,
- [!TextBlock.TextProperty] = property.WhenAnyValue(x => x.Priority).ToBinding(),
+ [!TextBlock.TextProperty] = property.GetObservable((nameof(property.Priority))).ToBinding(),
};
}
}
diff --git a/src/Avalonia.Diagnostics/Views/PropertyChangedExtenions.cs b/src/Avalonia.Diagnostics/Views/PropertyChangedExtenions.cs
new file mode 100644
index 0000000000..1d4ad24fd0
--- /dev/null
+++ b/src/Avalonia.Diagnostics/Views/PropertyChangedExtenions.cs
@@ -0,0 +1,30 @@
+using System;
+using System.ComponentModel;
+using System.Reactive.Linq;
+using System.Reflection;
+
+namespace Avalonia.Diagnostics.Views
+{
+ internal static class PropertyChangedExtenions
+ {
+ public static IObservable GetObservable(this INotifyPropertyChanged source, string propertyName)
+ {
+ Contract.Requires(source != null);
+ Contract.Requires(propertyName != null);
+
+ var property = source.GetType().GetTypeInfo().GetDeclaredProperty(propertyName);
+
+ if (property == null)
+ {
+ throw new ArgumentException($"Property '{propertyName}' not found on '{source}.");
+ }
+
+ return Observable.FromEventPattern(
+ e => source.PropertyChanged += e,
+ e => source.PropertyChanged -= e)
+ .Where(e => e.EventArgs.PropertyName == propertyName)
+ .Select(_ => (T)property.GetValue(source))
+ .StartWith((T)property.GetValue(source));
+ }
+ }
+}
diff --git a/src/Avalonia.Diagnostics/Views/TreePage.xaml.cs b/src/Avalonia.Diagnostics/Views/TreePage.xaml.cs
index 0a79aa90d7..7e4e5a8564 100644
--- a/src/Avalonia.Diagnostics/Views/TreePage.xaml.cs
+++ b/src/Avalonia.Diagnostics/Views/TreePage.xaml.cs
@@ -23,14 +23,14 @@ namespace Avalonia.Diagnostics.Views
protected void AddAdorner(object sender, PointerEventArgs e)
{
var node = (TreeNode)((Control)sender).DataContext;
- var layer = AdornerLayer.GetAdornerLayer(node.Control);
+ var layer = AdornerLayer.GetAdornerLayer(node.Visual);
if (layer != null)
{
_adorner = new Rectangle
{
Fill = new SolidColorBrush(0x80a0c5e8),
- [AdornerLayer.AdornedElementProperty] = node.Control,
+ [AdornerLayer.AdornedElementProperty] = node.Visual,
};
layer.Children.Add(_adorner);
diff --git a/src/Avalonia.Diagnostics/packages.config b/src/Avalonia.Diagnostics/packages.config
deleted file mode 100644
index df107dc625..0000000000
--- a/src/Avalonia.Diagnostics/packages.config
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
index 8a60d5d9c7..9d5436b2b9 100644
--- a/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
+++ b/src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
@@ -1,21 +1,7 @@
-
-
-
+
- 14.0
- Debug
- AnyCPU
- {7863EA94-F0FB-4386-BF8C-E5BFA761560A}
- Library
- Properties
- Avalonia.DotNetCoreRuntime
- Avalonia.DotNetCoreRuntime
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
-
-
- v5.0
+ netcoreapp1.0
+ false
true
@@ -36,54 +22,19 @@
4
bin\Release\Avalonia.DotNetCoreRuntime.XML
-
-
-
-
- SharedAssemblyInfo.cs
+ Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
- {b09b78d8-9b26-48b0-9149-d64a2f120f3f}
- Avalonia.Base
-
-
- {d2221c82-4a25-4583-9b43-d791e3f6820c}
- Avalonia.Controls
-
-
- {eb582467-6abb-43a1-b052-e981ba910e3a}
- Avalonia.Visuals
-
-
- {bb1f7bb5-6ad4-4776-94d9-c09d0a972658}
- Avalonia.Gtk3
-
-
- {7d2d3083-71dd-4cc9-8907-39a0d86fb322}
- Avalonia.Skia.Desktop.NetStandard
-
-
- {40759a76-d0f2-464e-8000-6ff0f5c4bd7c}
- Avalonia.Win32.NetStandard
-
-
+
+
+
+
+
+
+
-
-
\ No newline at end of file
diff --git a/src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs b/src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs
index b131488109..6aab8e0243 100644
--- a/src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs
+++ b/src/Avalonia.DotNetCoreRuntime/NetCoreRuntimePlatform.cs
@@ -5,6 +5,8 @@ using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
+using Microsoft.DotNet.PlatformAbstractions;
+using Microsoft.Extensions.DependencyModel;
namespace Avalonia.Shared.PlatformSupport
{
@@ -15,33 +17,26 @@ namespace Avalonia.Shared.PlatformSupport
static Assembly[] LoadAssemblies()
{
+ var assemblies = new List();
+ // Mostly copy-pasted from (MIT):
+ // https://github.com/StefH/System.AppDomain.Core/blob/0b35e676c2721aa367b96e62eb52c97ee0b43a70/src/System.AppDomain.NetCoreApp/AppDomain.cs
- var rv = new List();
- var entry = Assembly.GetEntryAssembly();
- rv.Add(entry);
- var queue = new Queue(entry.GetReferencedAssemblies());
- var aset = new HashSet(queue.Select(r => r.ToString()));
-
- while (queue.Count > 0)
+ foreach (var assemblyName in
+ DependencyContext.Default.GetRuntimeAssemblyNames(RuntimeEnvironment.GetRuntimeIdentifier()))
{
- Assembly asm;
try
{
- asm = Assembly.Load(queue.Dequeue());
- }
- catch (Exception e)
- {
- Debug.Write(e.ToString());
- continue;
+ var assembly = Assembly.Load(assemblyName);
+ // just load all types and skip this assembly if one or more types cannot be resolved
+ assembly.DefinedTypes.ToArray();
+ assemblies.Add(assembly);
}
- rv.Add(asm);
- foreach (var r in asm.GetReferencedAssemblies())
+ catch (Exception ex)
{
- if (aset.Add(r.ToString()))
- queue.Enqueue(r);
+ Debug.Write(ex.Message);
}
}
- return rv.Distinct().ToArray();
+ return assemblies.ToArray();
}
}
}
diff --git a/src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs b/src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..51ec3975c9
--- /dev/null
+++ b/src/Avalonia.DotNetCoreRuntime/Properties/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// 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.Reflection;
+
+[assembly: AssemblyTitle("Avalonia.DotNetCoreRuntime")]
diff --git a/src/Avalonia.DotNetCoreRuntime/project.json b/src/Avalonia.DotNetCoreRuntime/project.json
deleted file mode 100644
index d6ae90b33b..0000000000
--- a/src/Avalonia.DotNetCoreRuntime/project.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "supports": {},
- "dependencies": {
- "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
- "NETStandard.Library": "1.6.0",
- "System.Threading.ThreadPool": "4.3.0"
- },
- "frameworks": {
- "netstandard1.5": {}
- }
-}
\ No newline at end of file
diff --git a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
index fc7fdd2431..9a54cdbab0 100644
--- a/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
+++ b/src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
@@ -82,7 +82,13 @@ namespace Avalonia
private void LoadAssembliesInDirectory()
{
- foreach (var file in new FileInfo(Assembly.GetEntryAssembly().Location).Directory.EnumerateFiles("*.dll"))
+ var location = Assembly.GetEntryAssembly().Location;
+ if (string.IsNullOrWhiteSpace(location))
+ return;
+ var dir = new FileInfo(location).Directory;
+ if (dir == null)
+ return;
+ foreach (var file in dir.EnumerateFiles("*.dll"))
{
try
{
diff --git a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
index e87ec0b5a7..2fbcba40c8 100644
--- a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
+++ b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
@@ -1,5 +1,5 @@
-
+
Debug
@@ -9,7 +9,7 @@
Properties
Avalonia.DotNetFrameworkRuntime
Avalonia.DotNetFrameworkRuntime
- v4.5
+ v4.6.1
512
@@ -36,14 +36,6 @@
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\net45\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\net45\System.Reactive.Interfaces.dll
- True
-
@@ -74,16 +66,7 @@
Avalonia.Styling
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v2.ncrunchproject b/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.DotNetFrameworkRuntime/packages.config b/src/Avalonia.DotNetFrameworkRuntime/packages.config
deleted file mode 100644
index 1e93a8c9e7..0000000000
--- a/src/Avalonia.DotNetFrameworkRuntime/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs
index 12c040fab3..aab65fcbc7 100644
--- a/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs
+++ b/src/Avalonia.HtmlRenderer/Adapters/AvaloniaAdapter.cs
@@ -80,7 +80,7 @@ namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters
{
StartPoint = new RelativePoint(x, y, RelativeUnit.Relative),
EndPoint = new RelativePoint(1 - x, 1 - y, RelativeUnit.Relative),
- GradientStops =
+ GradientStops = new[]
{
new GradientStop(startColor, 0),
new GradientStop(endColor, 1)
diff --git a/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs
index 523da3508e..9a55768f6a 100644
--- a/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs
+++ b/src/Avalonia.HtmlRenderer/Adapters/ControlAdapter.cs
@@ -10,9 +10,11 @@
// - Sun Tsu,
// "The Art of War"
+using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Html;
using Avalonia.Input;
+using Avalonia.VisualTree;
using TheArtOfDev.HtmlRenderer.Adapters;
using TheArtOfDev.HtmlRenderer.Adapters.Entities;
using TheArtOfDev.HtmlRenderer.Core.Utils;
@@ -54,7 +56,8 @@ namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters
{
get
{
- return Util.Convert(MouseDevice.Instance.GetPosition(_control));
+ var pos = (_control.GetVisualRoot() as IInputRoot)?.MouseDevice?.Position ?? default(Point);
+ return Util.Convert(pos);
}
}
diff --git a/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs b/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs
index c9dd2a786c..93f8790741 100644
--- a/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs
+++ b/src/Avalonia.HtmlRenderer/Adapters/GraphicsAdapter.cs
@@ -117,7 +117,11 @@ namespace TheArtOfDev.HtmlRenderer.Avalonia.Adapters
FormattedText GetText(string str, RFont font)
{
var f = ((FontAdapter)font);
- return new FormattedText(str, f.Name, font.Size, f.FontStyle, TextAlignment.Left, f.Weight);
+ return new FormattedText
+ {
+ Text = str,
+ Typeface = new Typeface(f.Name, font.Size, f.FontStyle, f.Weight),
+ };
}
public override void MeasureString(string str, RFont font, double maxWidth, out int charFit, out double charFitWidth)
diff --git a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
index 8f16bad64a..f715217e42 100644
--- a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
+++ b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
@@ -1,22 +1,9 @@
-
-
-
+
- 10.0
- Debug
- AnyCPU
- {5FB2B005-0A7F-4DAD-ADD4-3ED01444E63D}
- Library
- Properties
- Avalonia.HtmlRenderer
- Avalonia.HtmlRenderer
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ False
+ False
+ false
true
@@ -36,7 +23,6 @@
4
-
@@ -51,6 +37,7 @@
+
@@ -137,65 +124,14 @@
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {D2221C82-4A25-4583-9B43-D791E3F6820C}
- Avalonia.Controls
-
-
- {62024B2D-53EB-4638-B26B-85EEAA54866E}
- Avalonia.Input
-
-
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Avalonia.Interactivity
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
-
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}
- Avalonia.Styling
-
+
+
+
+
+
+
+
+
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
-
-
-
-
- This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.v2.ncrunchproject b/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.HtmlRenderer/Compat/Api.cs b/src/Avalonia.HtmlRenderer/Compat/Api.cs
new file mode 100644
index 0000000000..798b697277
--- /dev/null
+++ b/src/Avalonia.HtmlRenderer/Compat/Api.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Net
+{
+ internal class AsyncCompletedEventArgs
+ {
+ public object UserState { get; set; }
+ public Exception Error { get; set; }
+ public bool Cancelled { get; set; }
+
+ public AsyncCompletedEventArgs(Exception error, bool cancelled, object userState)
+ {
+
+ }
+ }
+
+ class WebException : Exception
+ {
+ public object Response { get; set; }
+ }
+
+ class HttpWebResponse
+ {
+ public HttpStatusCode StatusCode { get; set; }
+ }
+}
diff --git a/src/Avalonia.HtmlRenderer/HtmlControl.cs b/src/Avalonia.HtmlRenderer/HtmlControl.cs
index ca8dcec2e1..0051f6427b 100644
--- a/src/Avalonia.HtmlRenderer/HtmlControl.cs
+++ b/src/Avalonia.HtmlRenderer/HtmlControl.cs
@@ -17,6 +17,7 @@ using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Threading;
+using Avalonia.VisualTree;
using TheArtOfDev.HtmlRenderer.Core;
using TheArtOfDev.HtmlRenderer.Core.Entities;
using TheArtOfDev.HtmlRenderer.Avalonia;
@@ -413,7 +414,7 @@ namespace Avalonia.Controls.Html
///
/// Handle mouse up to handle selection and link click.
///
- protected override void OnPointerReleased(PointerEventArgs e)
+ protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
LeftMouseButton = false;
@@ -512,7 +513,7 @@ namespace Avalonia.Controls.Html
protected virtual void InvokeMouseMove()
{
- _htmlContainer.HandleMouseMove(this, MouseDevice.Instance?.GetPosition(this) ?? default(Point));
+ _htmlContainer.HandleMouseMove(this, (this.GetVisualRoot() as IInputRoot)?.MouseDevice?.GetPosition(this) ?? default(Point));
}
///
diff --git a/src/Avalonia.HtmlRenderer/packages.config b/src/Avalonia.HtmlRenderer/packages.config
deleted file mode 100644
index b6a9c7823c..0000000000
--- a/src/Avalonia.HtmlRenderer/packages.config
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Input/Avalonia.Input.csproj b/src/Avalonia.Input/Avalonia.Input.csproj
index c1ed34c1c7..b5482ebce1 100644
--- a/src/Avalonia.Input/Avalonia.Input.csproj
+++ b/src/Avalonia.Input/Avalonia.Input.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {62024B2D-53EB-4638-B26B-85EEAA54866E}
- Library
- Properties
- Avalonia.Input
- Avalonia.Input
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -41,109 +26,16 @@
true
-
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Avalonia.Interactivity
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
+
+
+
+
+
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Input/Avalonia.Input.v2.ncrunchproject b/src/Avalonia.Input/Avalonia.Input.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Input/Avalonia.Input.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Input/FocusManager.cs b/src/Avalonia.Input/FocusManager.cs
index e5cc5a8557..102da6efc4 100644
--- a/src/Avalonia.Input/FocusManager.cs
+++ b/src/Avalonia.Input/FocusManager.cs
@@ -176,9 +176,10 @@ namespace Avalonia.Input
/// The event args.
private void OnPreviewPointerPressed(object sender, RoutedEventArgs e)
{
- if (sender == e.Source)
+ var ev = (PointerPressedEventArgs)e;
+
+ if (sender == e.Source && ev.MouseButton == MouseButton.Left)
{
- var ev = (PointerPressedEventArgs)e;
var element = (ev.Device?.Captured as IInputElement) ?? (e.Source as IInputElement);
if (element == null || !CanFocus(element))
diff --git a/src/Avalonia.Input/ICustomKeyboardNavigation.cs b/src/Avalonia.Input/ICustomKeyboardNavigation.cs
new file mode 100644
index 0000000000..de5f98e04b
--- /dev/null
+++ b/src/Avalonia.Input/ICustomKeyboardNavigation.cs
@@ -0,0 +1,15 @@
+// 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;
+
+namespace Avalonia.Input
+{
+ ///
+ /// Designates a control as handling its own keyboard navigation.
+ ///
+ public interface ICustomKeyboardNavigation
+ {
+ (bool handled, IInputElement next) GetNext(IInputElement element, NavigationDirection direction);
+ }
+}
diff --git a/src/Avalonia.Input/IInputDevice.cs b/src/Avalonia.Input/IInputDevice.cs
index 916f29376a..72fa2ab9bf 100644
--- a/src/Avalonia.Input/IInputDevice.cs
+++ b/src/Avalonia.Input/IInputDevice.cs
@@ -1,9 +1,16 @@
// 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 Avalonia.Input.Raw;
+
namespace Avalonia.Input
{
public interface IInputDevice
{
+ ///
+ /// Processes raw event. Is called after preprocessing by InputManager
+ ///
+ ///
+ void ProcessRawEvent(RawInputEventArgs ev);
}
}
diff --git a/src/Avalonia.Input/IInputElement.cs b/src/Avalonia.Input/IInputElement.cs
index 72f03d3ae5..5acb6aa777 100644
--- a/src/Avalonia.Input/IInputElement.cs
+++ b/src/Avalonia.Input/IInputElement.cs
@@ -1,7 +1,5 @@
// 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.Diagnostics.Contracts;
using System;
using System.Collections.Generic;
using Avalonia.Interactivity;
@@ -95,17 +93,17 @@ namespace Avalonia.Input
bool IsEnabledCore { get; }
///
- /// Gets or sets a value indicating whether the control is focused.
+ /// Gets a value indicating whether the control is focused.
///
bool IsFocused { get; }
///
- /// Gets or sets a value indicating whether the control is considered for hit testing.
+ /// Gets a value indicating whether the control is considered for hit testing.
///
bool IsHitTestVisible { get; }
///
- /// Gets or sets a value indicating whether the pointer is currently over the control.
+ /// Gets a value indicating whether the pointer is currently over the control.
///
bool IsPointerOver { get; }
diff --git a/src/Avalonia.Input/IInputRoot.cs b/src/Avalonia.Input/IInputRoot.cs
index 6c01bb9c0e..6b3e1e6bc5 100644
--- a/src/Avalonia.Input/IInputRoot.cs
+++ b/src/Avalonia.Input/IInputRoot.cs
@@ -1,6 +1,8 @@
// 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 JetBrains.Annotations;
+
namespace Avalonia.Input
{
///
@@ -27,5 +29,11 @@ namespace Avalonia.Input
/// Gets or sets a value indicating whether access keys are shown in the window.
///
bool ShowAccessKeys { get; set; }
+
+ ///
+ /// Gets associated mouse device
+ ///
+ [CanBeNull]
+ IMouseDevice MouseDevice { get; }
}
}
diff --git a/src/Avalonia.Input/IKeyboardDevice.cs b/src/Avalonia.Input/IKeyboardDevice.cs
index f27fec6907..1410476267 100644
--- a/src/Avalonia.Input/IKeyboardDevice.cs
+++ b/src/Avalonia.Input/IKeyboardDevice.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.ComponentModel;
namespace Avalonia.Input
{
@@ -26,7 +27,7 @@ namespace Avalonia.Input
Toggled = 2,
}
- public interface IKeyboardDevice : IInputDevice
+ public interface IKeyboardDevice : IInputDevice, INotifyPropertyChanged
{
IInputElement FocusedElement { get; }
diff --git a/src/Avalonia.Input/InputElement.cs b/src/Avalonia.Input/InputElement.cs
index 652b58f0b5..6385f7197b 100644
--- a/src/Avalonia.Input/InputElement.cs
+++ b/src/Avalonia.Input/InputElement.cs
@@ -473,7 +473,7 @@ namespace Avalonia.Input
/// Called before the event occurs.
///
/// The event args.
- protected virtual void OnPointerReleased(PointerEventArgs e)
+ protected virtual void OnPointerReleased(PointerReleasedEventArgs e)
{
}
diff --git a/src/Avalonia.Input/InputManager.cs b/src/Avalonia.Input/InputManager.cs
index 7aa609e65c..9e2d5ffea3 100644
--- a/src/Avalonia.Input/InputManager.cs
+++ b/src/Avalonia.Input/InputManager.cs
@@ -35,6 +35,7 @@ namespace Avalonia.Input
public void ProcessInput(RawInputEventArgs e)
{
_preProcess.OnNext(e);
+ e.Device?.ProcessRawEvent(e);
_process.OnNext(e);
_postProcess.OnNext(e);
}
diff --git a/src/Avalonia.Input/KeyboardDevice.cs b/src/Avalonia.Input/KeyboardDevice.cs
index 51af01f69b..d815f8082b 100644
--- a/src/Avalonia.Input/KeyboardDevice.cs
+++ b/src/Avalonia.Input/KeyboardDevice.cs
@@ -16,14 +16,6 @@ namespace Avalonia.Input
{
private IInputElement _focusedElement;
- public KeyboardDevice()
- {
- InputManager.Process
- .OfType()
- .Where(e => e.Device == this && !e.Handled)
- .Subscribe(ProcessRawEvent);
- }
-
public event PropertyChangedEventHandler PropertyChanged;
public static IKeyboardDevice Instance => AvaloniaLocator.Current.GetService();
@@ -77,8 +69,10 @@ namespace Avalonia.Input
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
- private void ProcessRawEvent(RawInputEventArgs e)
+ public void ProcessRawEvent(RawInputEventArgs e)
{
+ if(e.Handled)
+ return;
IInputElement element = FocusedElement;
if (element != null)
diff --git a/src/Avalonia.Input/KeyboardNavigationHandler.cs b/src/Avalonia.Input/KeyboardNavigationHandler.cs
index 57da49fa03..bf2b61d08b 100644
--- a/src/Avalonia.Input/KeyboardNavigationHandler.cs
+++ b/src/Avalonia.Input/KeyboardNavigationHandler.cs
@@ -2,7 +2,9 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using System.Linq;
using Avalonia.Input.Navigation;
+using Avalonia.VisualTree;
namespace Avalonia.Input
{
@@ -52,6 +54,31 @@ namespace Avalonia.Input
{
Contract.Requires(element != null);
+ var customHandler = element.GetSelfAndVisualAncestors()
+ .OfType()
+ .FirstOrDefault();
+
+ if (customHandler != null)
+ {
+ var (handled, next) = customHandler.GetNext(element, direction);
+
+ if (handled)
+ {
+ if (next != null)
+ {
+ return next;
+ }
+ else if (direction == NavigationDirection.Next || direction == NavigationDirection.Previous)
+ {
+ return TabNavigation.GetNextInTabOrder((IInputElement)customHandler, direction, true);
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
if (direction == NavigationDirection.Next || direction == NavigationDirection.Previous)
{
return TabNavigation.GetNextInTabOrder(element, direction);
diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs
index 2c0cb8656c..875a5ebaee 100644
--- a/src/Avalonia.Input/MouseDevice.cs
+++ b/src/Avalonia.Input/MouseDevice.cs
@@ -20,24 +20,7 @@ namespace Avalonia.Input
private int _clickCount;
private Rect _lastClickRect;
private uint _lastClickTime;
- private readonly List _pointerOvers = new List();
-
- ///
- /// Intializes a new instance of .
- ///
- public MouseDevice()
- {
- InputManager.Process
- .OfType()
- .Where(e => e.Device == this && !e.Handled)
- .Subscribe(ProcessRawEvent);
- }
-
- ///
- /// Gets the current mouse device instance.
- ///
- public static IMouseDevice Instance => AvaloniaLocator.Current.GetService();
-
+
///
/// Gets the control that is currently capturing by the mouse, if any.
///
@@ -51,12 +34,7 @@ namespace Avalonia.Input
get;
protected set;
}
-
- ///
- /// Gets the application's input manager.
- ///
- public IInputManager InputManager => AvaloniaLocator.Current.GetService();
-
+
///
/// Gets the mouse position, in screen coordinates.
///
@@ -87,6 +65,8 @@ namespace Avalonia.Input
/// The mouse position in the control's coordinates.
public Point GetPosition(IVisual relativeTo)
{
+ Contract.Requires(relativeTo != null);
+
Point p = default(Point);
IVisual v = relativeTo;
IVisual root = null;
@@ -101,8 +81,16 @@ namespace Avalonia.Input
return root.PointToClient(Position) - p;
}
+ public void ProcessRawEvent(RawInputEventArgs e)
+ {
+ if (!e.Handled && e is RawMouseEventArgs margs)
+ ProcessRawEvent(margs);
+ }
+
private void ProcessRawEvent(RawMouseEventArgs e)
{
+ Contract.Requires(e != null);
+
var mouse = (IMouseDevice)e.Device;
Position = e.Root.PointToScreen(e.Position);
@@ -141,11 +129,17 @@ namespace Avalonia.Input
private void LeaveWindow(IMouseDevice device, IInputRoot root)
{
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
ClearPointerOver(this, root);
}
private bool MouseDown(IMouseDevice device, uint timestamp, IInputElement root, Point p, MouseButton button, InputModifiers inputModifiers)
{
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
var hit = HitTest(root, p);
if (hit != null)
@@ -187,6 +181,9 @@ namespace Avalonia.Input
private bool MouseMove(IMouseDevice device, IInputRoot root, Point p, InputModifiers inputModifiers)
{
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
IInputElement source;
if (Captured == null)
@@ -195,8 +192,7 @@ namespace Avalonia.Input
}
else
{
- var elements = Captured.GetSelfAndVisualAncestors().OfType().ToList();
- SetPointerOver(this, root, elements);
+ SetPointerOver(this, root, Captured);
source = Captured;
}
@@ -208,12 +204,15 @@ namespace Avalonia.Input
InputModifiers = inputModifiers
};
- source.RaiseEvent(e);
+ source?.RaiseEvent(e);
return e.Handled;
}
private bool MouseUp(IMouseDevice device, IInputRoot root, Point p, MouseButton button, InputModifiers inputModifiers)
{
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
var hit = HitTest(root, p);
if (hit != null)
@@ -237,6 +236,9 @@ namespace Avalonia.Input
private bool MouseWheel(IMouseDevice device, IInputRoot root, Point p, Vector delta, InputModifiers inputModifiers)
{
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
var hit = HitTest(root, p);
if (hit != null)
@@ -260,6 +262,8 @@ namespace Avalonia.Input
private IInteractive GetSource(IVisual hit)
{
+ Contract.Requires(hit != null);
+
return Captured ??
(hit as IInteractive) ??
hit.GetSelfAndVisualAncestors().OfType().FirstOrDefault();
@@ -267,22 +271,28 @@ namespace Avalonia.Input
private IInputElement HitTest(IInputElement root, Point p)
{
+ Contract.Requires(root != null);
+
return Captured ?? root.InputHitTest(p);
}
private void ClearPointerOver(IPointerDevice device, IInputRoot root)
{
- foreach (var control in _pointerOvers.ToList())
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
+ var element = root.PointerOverElement;
+ var e = new PointerEventArgs
{
- PointerEventArgs e = new PointerEventArgs
- {
- RoutedEvent = InputElement.PointerLeaveEvent,
- Device = device,
- Source = control,
- };
+ RoutedEvent = InputElement.PointerLeaveEvent,
+ Device = device,
+ };
- _pointerOvers.Remove(control);
- control.RaiseEvent(e);
+ while (element != null)
+ {
+ e.Source = element;
+ element.RaiseEvent(e);
+ element = (IInputElement)element.VisualParent;
}
root.PointerOverElement = null;
@@ -290,40 +300,66 @@ namespace Avalonia.Input
private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, Point p)
{
- var elements = root.GetInputElementsAt(p).ToList();
- return SetPointerOver(device, root, elements);
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+
+ var element = root.InputHitTest(p);
+
+ if (element != root.PointerOverElement)
+ {
+ if (element != null)
+ {
+ SetPointerOver(device, root, element);
+ }
+ else
+ {
+ ClearPointerOver(device, root);
+ }
+ }
+
+ return element;
}
- private IInputElement SetPointerOver(IPointerDevice device, IInputRoot root, IList elements)
+ private void SetPointerOver(IPointerDevice device, IInputRoot root, IInputElement element)
{
- foreach (var control in _pointerOvers.Except(elements).ToList())
+ Contract.Requires(device != null);
+ Contract.Requires(root != null);
+ Contract.Requires(element != null);
+
+ IInputElement branch = null;
+
+ var e = new PointerEventArgs
{
- PointerEventArgs e = new PointerEventArgs
- {
- RoutedEvent = InputElement.PointerLeaveEvent,
- Device = device,
- Source = control,
- };
+ RoutedEvent = InputElement.PointerEnterEvent,
+ Device = device,
+ };
- _pointerOvers.Remove(control);
- control.RaiseEvent(e);
- }
+ var el = element;
- foreach (var control in elements.Except(_pointerOvers))
+ while (el != null)
{
- PointerEventArgs e = new PointerEventArgs
+ if (el.IsPointerOver)
{
- RoutedEvent = InputElement.PointerEnterEvent,
- Device = device,
- Source = control,
- };
+ branch = el;
+ break;
+ }
+
+ e.Source = el;
+ el.RaiseEvent(e);
+ el = (IInputElement)el.VisualParent;
+ }
+
+ el = root.PointerOverElement;
+ e.RoutedEvent = InputElement.PointerLeaveEvent;
- _pointerOvers.Add(control);
- control.RaiseEvent(e);
+ while (el != null && el != branch)
+ {
+ e.Source = el;
+ el.RaiseEvent(e);
+ el = (IInputElement)el.VisualParent;
}
- root.PointerOverElement = elements.FirstOrDefault() ?? root;
- return root.PointerOverElement;
+ root.PointerOverElement = element;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/Avalonia.Input/Navigation/DirectionalNavigation.cs b/src/Avalonia.Input/Navigation/DirectionalNavigation.cs
index b2f7a35799..75cb3a39e8 100644
--- a/src/Avalonia.Input/Navigation/DirectionalNavigation.cs
+++ b/src/Avalonia.Input/Navigation/DirectionalNavigation.cs
@@ -41,10 +41,10 @@ namespace Avalonia.Input.Navigation
{
case KeyboardNavigationMode.Continue:
return GetNextInContainer(element, container, direction) ??
- GetFirstInNextContainer(element, direction);
+ GetFirstInNextContainer(element, element, direction);
case KeyboardNavigationMode.Cycle:
return GetNextInContainer(element, container, direction) ??
- GetFocusableDescendent(container, direction);
+ GetFocusableDescendant(container, direction);
case KeyboardNavigationMode.Contained:
return GetNextInContainer(element, container, direction);
default:
@@ -53,7 +53,7 @@ namespace Avalonia.Input.Navigation
}
else
{
- return GetFocusableDescendents(element).FirstOrDefault();
+ return GetFocusableDescendants(element).FirstOrDefault();
}
}
@@ -71,24 +71,24 @@ namespace Avalonia.Input.Navigation
}
///
- /// Gets the first or last focusable descendent of the specified element.
+ /// Gets the first or last focusable descendant of the specified element.
///
/// The element.
/// The direction to search.
/// The element or null if not found.##
- private static IInputElement GetFocusableDescendent(IInputElement container, NavigationDirection direction)
+ private static IInputElement GetFocusableDescendant(IInputElement container, NavigationDirection direction)
{
return IsForward(direction) ?
- GetFocusableDescendents(container).FirstOrDefault() :
- GetFocusableDescendents(container).LastOrDefault();
+ GetFocusableDescendants(container).FirstOrDefault() :
+ GetFocusableDescendants(container).LastOrDefault();
}
///
- /// Gets the focusable descendents of the specified element.
+ /// Gets the focusable descendants of the specified element.
///
/// The element.
- /// The element's focusable descendents.
- private static IEnumerable GetFocusableDescendents(IInputElement element)
+ /// The element's focusable descendants.
+ private static IEnumerable GetFocusableDescendants(IInputElement element)
{
var children = element.GetVisualChildren().OfType();
@@ -99,11 +99,11 @@ namespace Avalonia.Input.Navigation
yield return child;
}
- if (child.CanFocusDescendents())
+ if (child.CanFocusDescendants())
{
- foreach (var descendent in GetFocusableDescendents(child))
+ foreach (var descendant in GetFocusableDescendants(child))
{
- yield return descendent;
+ yield return descendant;
}
}
}
@@ -123,11 +123,11 @@ namespace Avalonia.Input.Navigation
{
if (direction == NavigationDirection.Down)
{
- var descendent = GetFocusableDescendents(element).FirstOrDefault();
+ var descendant = GetFocusableDescendants(element).FirstOrDefault();
- if (descendent != null)
+ if (descendant != null)
{
- return descendent;
+ return descendant;
}
}
@@ -156,11 +156,11 @@ namespace Avalonia.Input.Navigation
if (element != null && direction == NavigationDirection.Up)
{
- var descendent = GetFocusableDescendents(element).LastOrDefault();
+ var descendant = GetFocusableDescendants(element).LastOrDefault();
- if (descendent != null)
+ if (descendant != null)
{
- return descendent;
+ return descendant;
}
}
@@ -173,10 +173,12 @@ namespace Avalonia.Input.Navigation
///
/// Gets the first item that should be focused in the next container.
///
+ /// The element being navigated away from.
/// The container.
/// The direction of the search.
/// The first element, or null if there are no more elements.
private static IInputElement GetFirstInNextContainer(
+ IInputElement element,
IInputElement container,
NavigationDirection direction)
{
@@ -193,13 +195,23 @@ namespace Avalonia.Input.Navigation
var siblings = parent.GetVisualChildren()
.OfType()
- .Where(FocusExtensions.CanFocusDescendents);
+ .Where(FocusExtensions.CanFocusDescendants);
var sibling = isForward ?
siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() :
siblings.TakeWhile(x => x != container).LastOrDefault();
if (sibling != null)
{
+ if (sibling is ICustomKeyboardNavigation custom)
+ {
+ var (handled, customNext) = custom.GetNext(element, direction);
+
+ if (handled)
+ {
+ return customNext;
+ }
+ }
+
if (sibling.CanFocus())
{
next = sibling;
@@ -207,21 +219,21 @@ namespace Avalonia.Input.Navigation
else
{
next = isForward ?
- GetFocusableDescendents(sibling).FirstOrDefault() :
- GetFocusableDescendents(sibling).LastOrDefault();
+ GetFocusableDescendants(sibling).FirstOrDefault() :
+ GetFocusableDescendants(sibling).LastOrDefault();
}
}
if (next == null)
{
- next = GetFirstInNextContainer(parent, direction);
+ next = GetFirstInNextContainer(element, parent, direction);
}
}
else
{
next = isForward ?
- GetFocusableDescendents(container).FirstOrDefault() :
- GetFocusableDescendents(container).LastOrDefault();
+ GetFocusableDescendants(container).FirstOrDefault() :
+ GetFocusableDescendants(container).LastOrDefault();
}
return next;
diff --git a/src/Avalonia.Input/Navigation/FocusExtensions.cs b/src/Avalonia.Input/Navigation/FocusExtensions.cs
index 36fda1abb1..41e7c4cd7b 100644
--- a/src/Avalonia.Input/Navigation/FocusExtensions.cs
+++ b/src/Avalonia.Input/Navigation/FocusExtensions.cs
@@ -16,10 +16,10 @@ namespace Avalonia.Input.Navigation
public static bool CanFocus(this IInputElement e) => e.Focusable && e.IsEnabledCore && e.IsVisible;
///
- /// Checks if descendents of the specified element can be focused.
+ /// Checks if descendants of the specified element can be focused.
///
/// The element.
- /// True if descendents of the element can be focused.
- public static bool CanFocusDescendents(this IInputElement e) => e.IsEnabledCore && e.IsVisible;
+ /// True if descendants of the element can be focused.
+ public static bool CanFocusDescendants(this IInputElement e) => e.IsEnabledCore && e.IsVisible;
}
}
diff --git a/src/Avalonia.Input/Navigation/TabNavigation.cs b/src/Avalonia.Input/Navigation/TabNavigation.cs
index bc3826d90e..6e077e887f 100644
--- a/src/Avalonia.Input/Navigation/TabNavigation.cs
+++ b/src/Avalonia.Input/Navigation/TabNavigation.cs
@@ -18,13 +18,17 @@ namespace Avalonia.Input.Navigation
///
/// The element.
/// The tab direction. Must be Next or Previous.
+ ///
+ /// If true will not descend into to find next control.
+ ///
///
/// The next element in the specified direction, or null if
/// was the last in the requested direction.
///
public static IInputElement GetNextInTabOrder(
IInputElement element,
- NavigationDirection direction)
+ NavigationDirection direction,
+ bool outsideElement = false)
{
Contract.Requires(element != null);
Contract.Requires(
@@ -40,42 +44,43 @@ namespace Avalonia.Input.Navigation
switch (mode)
{
case KeyboardNavigationMode.Continue:
- return GetNextInContainer(element, container, direction) ??
- GetFirstInNextContainer(element, direction);
+ return GetNextInContainer(element, container, direction, outsideElement) ??
+ GetFirstInNextContainer(element, element, direction);
case KeyboardNavigationMode.Cycle:
- return GetNextInContainer(element, container, direction) ??
- GetFocusableDescendent(container, direction);
+ return GetNextInContainer(element, container, direction, outsideElement) ??
+ GetFocusableDescendant(container, direction);
case KeyboardNavigationMode.Contained:
- return GetNextInContainer(element, container, direction);
+ return GetNextInContainer(element, container, direction, outsideElement);
default:
- return GetFirstInNextContainer(container, direction);
+ return GetFirstInNextContainer(element, container, direction);
}
}
else
{
- return GetFocusableDescendents(element).FirstOrDefault();
+ return GetFocusableDescendants(element, direction).FirstOrDefault();
}
}
///
- /// Gets the first or last focusable descendent of the specified element.
+ /// Gets the first or last focusable descendant of the specified element.
///
/// The element.
/// The direction to search.
/// The element or null if not found.##
- private static IInputElement GetFocusableDescendent(IInputElement container, NavigationDirection direction)
+ private static IInputElement GetFocusableDescendant(IInputElement container, NavigationDirection direction)
{
return direction == NavigationDirection.Next ?
- GetFocusableDescendents(container).FirstOrDefault() :
- GetFocusableDescendents(container).LastOrDefault();
+ GetFocusableDescendants(container, direction).FirstOrDefault() :
+ GetFocusableDescendants(container, direction).LastOrDefault();
}
///
- /// Gets the focusable descendents of the specified element.
+ /// Gets the focusable descendants of the specified element.
///
/// The element.
- /// The element's focusable descendents.
- private static IEnumerable GetFocusableDescendents(IInputElement element)
+ /// The tab direction. Must be Next or Previous.
+ /// The element's focusable descendants.
+ private static IEnumerable GetFocusableDescendants(IInputElement element, NavigationDirection direction)
{
var mode = KeyboardNavigation.GetTabNavigation((InputElement)element);
@@ -103,16 +108,25 @@ namespace Avalonia.Input.Navigation
foreach (var child in children)
{
- if (child.CanFocus())
+ var customNext = GetCustomNext(child, direction);
+
+ if (customNext.handled)
{
- yield return child;
+ yield return customNext.next;
}
-
- if (child.CanFocusDescendents())
+ else
{
- foreach (var descendent in GetFocusableDescendents(child))
+ if (child.CanFocus())
{
- yield return descendent;
+ yield return child;
+ }
+
+ if (child.CanFocusDescendants())
+ {
+ foreach (var descendant in GetFocusableDescendants(child, direction))
+ {
+ yield return descendant;
+ }
}
}
}
@@ -124,19 +138,23 @@ namespace Avalonia.Input.Navigation
/// The starting element/
/// The container.
/// The direction.
+ ///
+ /// If true will not descend into to find next control.
+ ///
/// The next element, or null if the element is the last.
private static IInputElement GetNextInContainer(
IInputElement element,
IInputElement container,
- NavigationDirection direction)
+ NavigationDirection direction,
+ bool outsideElement)
{
- if (direction == NavigationDirection.Next)
+ if (direction == NavigationDirection.Next && !outsideElement)
{
- var descendent = GetFocusableDescendents(element).FirstOrDefault();
+ var descendant = GetFocusableDescendants(element, direction).FirstOrDefault();
- if (descendent != null)
+ if (descendant != null)
{
- return descendent;
+ return descendant;
}
}
@@ -167,11 +185,11 @@ namespace Avalonia.Input.Navigation
if (element != null && direction == NavigationDirection.Previous)
{
- var descendent = GetFocusableDescendents(element).LastOrDefault();
+ var descendant = GetFocusableDescendants(element, direction).LastOrDefault();
- if (descendent != null)
+ if (descendant != null)
{
- return descendent;
+ return descendant;
}
}
@@ -184,10 +202,12 @@ namespace Avalonia.Input.Navigation
///
/// Gets the first item that should be focused in the next container.
///
+ /// The element being navigated away from.
/// The container.
/// The direction of the search.
/// The first element, or null if there are no more elements.
private static IInputElement GetFirstInNextContainer(
+ IInputElement element,
IInputElement container,
NavigationDirection direction)
{
@@ -203,13 +223,20 @@ namespace Avalonia.Input.Navigation
var siblings = parent.GetVisualChildren()
.OfType()
- .Where(FocusExtensions.CanFocusDescendents);
+ .Where(FocusExtensions.CanFocusDescendants);
var sibling = direction == NavigationDirection.Next ?
siblings.SkipWhile(x => x != container).Skip(1).FirstOrDefault() :
siblings.TakeWhile(x => x != container).LastOrDefault();
if (sibling != null)
{
+ var customNext = GetCustomNext(sibling, direction);
+
+ if (customNext.handled)
+ {
+ return customNext.next;
+ }
+
if (sibling.CanFocus())
{
next = sibling;
@@ -217,24 +244,34 @@ namespace Avalonia.Input.Navigation
else
{
next = direction == NavigationDirection.Next ?
- GetFocusableDescendents(sibling).FirstOrDefault() :
- GetFocusableDescendents(sibling).LastOrDefault();
+ GetFocusableDescendants(sibling, direction).FirstOrDefault() :
+ GetFocusableDescendants(sibling, direction).LastOrDefault();
}
}
if (next == null)
{
- next = GetFirstInNextContainer(parent, direction);
+ next = GetFirstInNextContainer(element, parent, direction);
}
}
else
{
next = direction == NavigationDirection.Next ?
- GetFocusableDescendents(container).FirstOrDefault() :
- GetFocusableDescendents(container).LastOrDefault();
+ GetFocusableDescendants(container, direction).FirstOrDefault() :
+ GetFocusableDescendants(container, direction).LastOrDefault();
}
return next;
}
+
+ private static (bool handled, IInputElement next) GetCustomNext(IInputElement element, NavigationDirection direction)
+ {
+ if (element is ICustomKeyboardNavigation custom)
+ {
+ return custom.GetNext(element, direction);
+ }
+
+ return (false, null);
+ }
}
}
diff --git a/src/Avalonia.Input/packages.config b/src/Avalonia.Input/packages.config
deleted file mode 100644
index 9f732f1bcb..0000000000
--- a/src/Avalonia.Input/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
index 0d81690de0..9d22de86b3 100644
--- a/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
+++ b/src/Avalonia.Interactivity/Avalonia.Interactivity.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {6B0ED19D-A08B-461C-A9D9-A9EE40B0C06B}
- Library
- Properties
- Avalonia.Interactivity
- Avalonia.Interactivity
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -41,63 +26,15 @@
true
-
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Avalonia.Layout
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
+
+
+
+
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Interactivity/Avalonia.Interactivity.v2.ncrunchproject b/src/Avalonia.Interactivity/Avalonia.Interactivity.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Interactivity/Avalonia.Interactivity.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Interactivity/InteractiveExtensions.cs b/src/Avalonia.Interactivity/InteractiveExtensions.cs
index 2507fc6866..b03590951b 100644
--- a/src/Avalonia.Interactivity/InteractiveExtensions.cs
+++ b/src/Avalonia.Interactivity/InteractiveExtensions.cs
@@ -1,8 +1,10 @@
// 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.Collections.Generic;
using System.Linq;
+using System.Reactive.Linq;
namespace Avalonia.Interactivity
{
@@ -11,12 +13,36 @@ namespace Avalonia.Interactivity
///
public static class InteractiveExtensions
{
+ ///
+ /// Gets an observable for a .
+ ///
+ /// The object to listen for events on.
+ /// The routed event.
+ /// The routing strategies to listen to.
+ /// Whether handled events should also be listened for.
+ ///
+ /// An observable which fires each time the event is raised.
+ ///
+ public static IObservable GetObservable(
+ this IInteractive o,
+ RoutedEvent routedEvent,
+ RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
+ bool handledEventsToo = false)
+ where TEventArgs : RoutedEventArgs
+ {
+ return Observable.Create(x => o.AddHandler(
+ routedEvent,
+ (_, e) => x.OnNext(e),
+ routes,
+ handledEventsToo));
+ }
+
///
/// Gets the route for bubbling events from the specified interactive.
///
/// The interactive.
/// The event route.
- public static IEnumerable GetBubbleEventRoute(this IInteractive interactive)
+ internal static IEnumerable GetBubbleEventRoute(this IInteractive interactive)
{
while (interactive != null)
{
@@ -30,7 +56,7 @@ namespace Avalonia.Interactivity
///
/// The interactive.
/// The event route.
- public static IEnumerable GetTunnelEventRoute(this IInteractive interactive)
+ internal static IEnumerable GetTunnelEventRoute(this IInteractive interactive)
{
return interactive.GetBubbleEventRoute().Reverse();
}
diff --git a/src/Avalonia.Interactivity/packages.config b/src/Avalonia.Interactivity/packages.config
deleted file mode 100644
index 9f732f1bcb..0000000000
--- a/src/Avalonia.Interactivity/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Layout/Avalonia.Layout.csproj b/src/Avalonia.Layout/Avalonia.Layout.csproj
index 41b545b5cb..d0260391d8 100644
--- a/src/Avalonia.Layout/Avalonia.Layout.csproj
+++ b/src/Avalonia.Layout/Avalonia.Layout.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {42472427-4774-4C81-8AFF-9F27B8E31721}
- Library
- Properties
- Avalonia
- Avalonia.Layout
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -41,59 +26,14 @@
true
-
-
- {D211E587-D8BC-45B9-95A4-F297C8FA5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
+
+
+
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Layout/Avalonia.Layout.v2.ncrunchproject b/src/Avalonia.Layout/Avalonia.Layout.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Layout/Avalonia.Layout.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Layout/IEmbeddedLayoutRoot.cs b/src/Avalonia.Layout/IEmbeddedLayoutRoot.cs
new file mode 100644
index 0000000000..24f0ccd82e
--- /dev/null
+++ b/src/Avalonia.Layout/IEmbeddedLayoutRoot.cs
@@ -0,0 +1,10 @@
+namespace Avalonia.Layout
+{
+ ///
+ /// A special layout root with enforced size for Arrange pass
+ ///
+ public interface IEmbeddedLayoutRoot : ILayoutRoot
+ {
+ Size AllocatedSize { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/Avalonia.Layout/LayoutManager.cs b/src/Avalonia.Layout/LayoutManager.cs
index b7b83bf852..3244f5e7dc 100644
--- a/src/Avalonia.Layout/LayoutManager.cs
+++ b/src/Avalonia.Layout/LayoutManager.cs
@@ -14,8 +14,8 @@ namespace Avalonia.Layout
///
public class LayoutManager : ILayoutManager
{
- private readonly HashSet _toMeasure = new HashSet();
- private readonly HashSet _toArrange = new HashSet();
+ private readonly Queue _toMeasure = new Queue();
+ private readonly Queue _toArrange = new Queue();
private bool _queued;
private bool _running;
@@ -30,8 +30,18 @@ namespace Avalonia.Layout
Contract.Requires(control != null);
Dispatcher.UIThread.VerifyAccess();
- _toMeasure.Add(control);
- _toArrange.Add(control);
+ if (!control.IsAttachedToVisualTree)
+ {
+#if DEBUG
+ throw new AvaloniaInternalException(
+ "LayoutManager.InvalidateMeasure called on a control that is detached from the visual tree.");
+#else
+ return;
+#endif
+ }
+
+ _toMeasure.Enqueue(control);
+ _toArrange.Enqueue(control);
QueueLayoutPass();
}
@@ -41,7 +51,17 @@ namespace Avalonia.Layout
Contract.Requires(control != null);
Dispatcher.UIThread.VerifyAccess();
- _toArrange.Add(control);
+ if (!control.IsAttachedToVisualTree)
+ {
+#if DEBUG
+ throw new AvaloniaInternalException(
+ "LayoutManager.InvalidateArrange called on a control that is detached from the visual tree.");
+#else
+ return;
+#endif
+ }
+
+ _toArrange.Enqueue(control);
QueueLayoutPass();
}
@@ -108,8 +128,12 @@ namespace Avalonia.Layout
{
while (_toMeasure.Count > 0)
{
- var next = _toMeasure.First();
- Measure(next);
+ var control = _toMeasure.Dequeue();
+
+ if (!control.IsMeasureValid && control.IsAttachedToVisualTree)
+ {
+ Measure(control);
+ }
}
}
@@ -117,53 +141,62 @@ namespace Avalonia.Layout
{
while (_toArrange.Count > 0 && _toMeasure.Count == 0)
{
- var next = _toArrange.First();
- Arrange(next);
+ var control = _toArrange.Dequeue();
+
+ if (!control.IsArrangeValid && control.IsAttachedToVisualTree)
+ {
+ Arrange(control);
+ }
}
}
private void Measure(ILayoutable control)
{
- var root = control as ILayoutRoot;
- var parent = control.VisualParent as ILayoutable;
-
- if (root != null)
- {
- root.Measure(root.MaxClientSize);
- }
- else if (parent != null)
+ // Controls closest to the visual root need to be arranged first. We don't try to store
+ // ordered invalidation lists, instead we traverse the tree upwards, measuring the
+ // controls closest to the root first. This has been shown by benchmarks to be the
+ // fastest and most memory-efficent algorithm.
+ if (control.VisualParent is ILayoutable parent)
{
Measure(parent);
}
- if (!control.IsMeasureValid)
+ // If the control being measured has IsMeasureValid == true here then its measure was
+ // handed by an ancestor and can be ignored. The measure may have also caused the
+ // control to be removed.
+ if (!control.IsMeasureValid && control.IsAttachedToVisualTree)
{
- control.Measure(control.PreviousMeasure.Value);
+ if (control is ILayoutRoot root)
+ {
+ root.Measure(Size.Infinity);
+ }
+ else
+ {
+ control.Measure(control.PreviousMeasure.Value);
+ }
}
-
- _toMeasure.Remove(control);
}
private void Arrange(ILayoutable control)
{
- var root = control as ILayoutRoot;
- var parent = control.VisualParent as ILayoutable;
-
- if (root != null)
- {
- root.Arrange(new Rect(root.DesiredSize));
- }
- else if (parent != null)
+ if (control.VisualParent is ILayoutable parent)
{
Arrange(parent);
}
- if (control.PreviousArrange.HasValue)
+ if (!control.IsArrangeValid && control.IsAttachedToVisualTree)
{
- control.Arrange(control.PreviousArrange.Value);
+ if (control is IEmbeddedLayoutRoot embeddedRoot)
+ control.Arrange(new Rect(embeddedRoot.AllocatedSize));
+ else if (control is ILayoutRoot root)
+ control.Arrange(new Rect(root.DesiredSize));
+ else if (control.PreviousArrange != null)
+ {
+ // Has been observed that PreviousArrange sometimes is null, probably a bug somewhere else.
+ // Condition observed: control.VisualParent is Scrollbar, control is Border.
+ control.Arrange(control.PreviousArrange.Value);
+ }
}
-
- _toArrange.Remove(control);
}
private void QueueLayoutPass()
diff --git a/src/Avalonia.Layout/Layoutable.cs b/src/Avalonia.Layout/Layoutable.cs
index 5abd6c52f7..523c720e2f 100644
--- a/src/Avalonia.Layout/Layoutable.cs
+++ b/src/Avalonia.Layout/Layoutable.cs
@@ -367,6 +367,14 @@ namespace Avalonia.Layout
}
}
+
+ ///
+ /// Called by InvalidateMeasure
+ ///
+ protected virtual void OnMeasureInvalidated()
+ {
+ }
+
///
/// Invalidates the measurement of the control and queues a new layout pass.
///
@@ -378,8 +386,13 @@ namespace Avalonia.Layout
IsMeasureValid = false;
IsArrangeValid = false;
- LayoutManager.Instance?.InvalidateMeasure(this);
- InvalidateVisual();
+
+ if (((ILayoutable)this).IsAttachedToVisualTree)
+ {
+ LayoutManager.Instance?.InvalidateMeasure(this);
+ InvalidateVisual();
+ }
+ OnMeasureInvalidated();
}
}
@@ -393,8 +406,12 @@ namespace Avalonia.Layout
Logger.Verbose(LogArea.Layout, this, "Invalidated arrange");
IsArrangeValid = false;
- LayoutManager.Instance?.InvalidateArrange(this);
- InvalidateVisual();
+
+ if (((ILayoutable)this).IsAttachedToVisualTree)
+ {
+ LayoutManager.Instance?.InvalidateArrange(this);
+ InvalidateVisual();
+ }
}
}
@@ -456,10 +473,9 @@ namespace Avalonia.Layout
ApplyTemplate();
- var constrained = LayoutHelper
- .ApplyLayoutConstraints(this, availableSize)
- .Deflate(margin);
-
+ var constrained = LayoutHelper.ApplyLayoutConstraints(
+ this,
+ availableSize.Deflate(margin));
var measured = MeasureOverride(constrained);
var width = measured.Width;
@@ -613,7 +629,7 @@ namespace Avalonia.Layout
///
protected override sealed void OnVisualParentChanged(IVisual oldParent, IVisual newParent)
{
- foreach (ILayoutable i in this.GetSelfAndVisualDescendents())
+ foreach (ILayoutable i in this.GetSelfAndVisualDescendants())
{
i.InvalidateMeasure();
}
diff --git a/src/Avalonia.Layout/packages.config b/src/Avalonia.Layout/packages.config
deleted file mode 100644
index 9f732f1bcb..0000000000
--- a/src/Avalonia.Layout/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
index 0fb85db795..508ede7f7d 100644
--- a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
+++ b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
@@ -1,20 +1,7 @@
-
-
-
+
- 10.0
- Debug
- AnyCPU
- {B61B66A3-B82D-4875-8001-89D3394FE0C9}
- Library
- Properties
- Avalonia.Logging.Serilog
- Avalonia.Logging.Serilog
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
+ netstandard1.3
+ false
true
@@ -37,30 +24,7 @@
true
-
-
+
-
-
- ..\..\packages\Serilog.1.5.14\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+MonoTouch10\Serilog.dll
- True
-
-
-
-
-
-
-
- {b09b78d8-9b26-48b0-9149-d64a2f120f3f}
- Avalonia.Base
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.v2.ncrunchproject b/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Logging.Serilog/packages.config b/src/Avalonia.Logging.Serilog/packages.config
deleted file mode 100644
index dbc72b5331..0000000000
--- a/src/Avalonia.Logging.Serilog/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
index 98cf115eaf..2d66b62eab 100644
--- a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
+++ b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
@@ -1,27 +1,15 @@
-
-
-
+
- 10.0
- Debug
- AnyCPU
- {6417B24E-49C2-4985-8DB2-3AB9D898EC91}
- Library
- Properties
- Avalonia.ReactiveUI
- Avalonia.ReactiveUI
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile259
- v4.5
+ netstandard1.3
+ False
+ false
true
full
false
bin\Debug\
- TRACE;DEBUG;MONO PORTABLE
+ TRACE;DEBUG;MONO PORTABLE;NETSTANDARD1_1
prompt
4
@@ -29,15 +17,19 @@
pdbonly
true
bin\Release\
- TRACE;MONO PORTABLE
+ TRACE;MONO PORTABLE;RELEASE;NETSTANDARD1_1
prompt
4
+
+
+
+
@@ -65,9 +57,7 @@
-
- Code
-
+
@@ -87,35 +77,15 @@
-
- ..\..\packages\Splat.1.6.2\lib\Portable-net45+win+wpa81+wp80\Splat.dll
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.0\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.0\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
\ No newline at end of file
diff --git a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.v2.ncrunchproject b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.ReactiveUI/Shims.cs b/src/Avalonia.ReactiveUI/Shims.cs
new file mode 100644
index 0000000000..2729a68d6f
--- /dev/null
+++ b/src/Avalonia.ReactiveUI/Shims.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace System.Runtime.Serialization
+{
+ class IgnoreDataMemberAttribute : Attribute
+ {
+ }
+
+ class DataMemberAttribute : Attribute
+ {
+ }
+ class OnDeserializedAttribute : Attribute
+ {
+ }
+
+ class DataContractAttribute : Attribute
+ {
+ }
+
+ class StreamingContext { }
+}
+
+namespace System.Diagnostics.Contracts
+{
+ static class Contract
+ {
+ public static void Requires(bool condition)
+ {
+
+ }
+ }
+}
diff --git a/src/Avalonia.ReactiveUI/packages.config b/src/Avalonia.ReactiveUI/packages.config
deleted file mode 100644
index f10d6d8873..0000000000
--- a/src/Avalonia.ReactiveUI/packages.config
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj
index d38406caa7..6bf37b522b 100644
--- a/src/Avalonia.Styling/Avalonia.Styling.csproj
+++ b/src/Avalonia.Styling/Avalonia.Styling.csproj
@@ -1,22 +1,7 @@
-
-
-
+
- 11.0
- Debug
- AnyCPU
- {F1BAA01A-F176-4C6A-B39D-5B40BB1B148F}
- Library
- Properties
- Avalonia
- Avalonia.Styling
- en-US
- 512
- {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
- Profile7
- v4.5
-
-
+ netstandard1.3
+ false
true
@@ -44,84 +29,11 @@
Properties\SharedAssemblyInfo.cs
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ..\..\packages\System.Reactive.Core.3.0.0\lib\netstandard1.1\System.Reactive.Core.dll
- True
-
-
- ..\..\packages\System.Reactive.Interfaces.3.0.0\lib\netstandard1.0\System.Reactive.Interfaces.dll
- True
-
-
- ..\..\packages\System.Reactive.Linq.3.0.0\lib\netstandard1.1\System.Reactive.Linq.dll
- True
-
-
- ..\..\packages\System.Reactive.PlatformServices.3.0.0\lib\netstandard1.0\System.Reactive.PlatformServices.dll
- True
-
+
+
+
-
-
-
-
-
-
-
- {d211e587-d8bc-45b9-95a4-f297c8fa5200}
- Avalonia.Animation
-
-
- {B09B78D8-9B26-48B0-9149-D64A2F120F3F}
- Avalonia.Base
-
-
- {EB582467-6ABB-43A1-B052-E981BA910E3A}
- Avalonia.Visuals
-
-
-
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Styling/Avalonia.Styling.v2.ncrunchproject b/src/Avalonia.Styling/Avalonia.Styling.v2.ncrunchproject
deleted file mode 100644
index 30815b1937..0000000000
--- a/src/Avalonia.Styling/Avalonia.Styling.v2.ncrunchproject
+++ /dev/null
@@ -1,26 +0,0 @@
-
- true
- 1000
- false
- false
- false
- true
- false
- false
- false
- false
- false
- true
- true
- false
- true
- true
- true
- 60000
-
-
-
- AutoDetect
- STA
- x86
-
\ No newline at end of file
diff --git a/src/Avalonia.Styling/Controls/NameScope.cs b/src/Avalonia.Styling/Controls/NameScope.cs
index 4c5875479e..8b5bd81d3c 100644
--- a/src/Avalonia.Styling/Controls/NameScope.cs
+++ b/src/Avalonia.Styling/Controls/NameScope.cs
@@ -50,7 +50,7 @@ namespace Avalonia.Controls
return result;
}
- visual = (visual as ILogical).LogicalParent as Visual;
+ visual = (visual as ILogical)?.LogicalParent as Visual;
}
return null;
diff --git a/src/Avalonia.Styling/LogicalTree/ILogical.cs b/src/Avalonia.Styling/LogicalTree/ILogical.cs
index f2291b42e9..006a9f5cc1 100644
--- a/src/Avalonia.Styling/LogicalTree/ILogical.cs
+++ b/src/Avalonia.Styling/LogicalTree/ILogical.cs
@@ -36,6 +36,16 @@ namespace Avalonia.LogicalTree
///
IAvaloniaReadOnlyList LogicalChildren { get; }
+ ///
+ /// Notifies the control that it is being attached to a rooted logical tree.
+ ///
+ /// The event args.
+ ///
+ /// This method will be called automatically by the framework, you should not need to call
+ /// this method yourself.
+ ///
+ void NotifyAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e);
+
///
/// Notifies the control that it is being detached from a rooted logical tree.
///
diff --git a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs
index 0d9c0f6daa..a72a558258 100644
--- a/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs
+++ b/src/Avalonia.Styling/LogicalTree/LogicalExtensions.cs
@@ -37,15 +37,15 @@ namespace Avalonia.LogicalTree
return logical.LogicalChildren;
}
- public static IEnumerable GetLogicalDescendents(this ILogical logical)
+ public static IEnumerable GetLogicalDescendants(this ILogical logical)
{
foreach (ILogical child in logical.LogicalChildren)
{
yield return child;
- foreach (ILogical descendent in child.GetLogicalDescendents())
+ foreach (ILogical descendant in child.GetLogicalDescendants())
{
- yield return descendent;
+ yield return descendant;
}
}
}
diff --git a/src/Avalonia.Styling/Styling/DescendentSelector.cs b/src/Avalonia.Styling/Styling/DescendentSelector.cs
index 525f31cbf1..943b3f0161 100644
--- a/src/Avalonia.Styling/Styling/DescendentSelector.cs
+++ b/src/Avalonia.Styling/Styling/DescendentSelector.cs
@@ -7,16 +7,16 @@ using Avalonia.LogicalTree;
namespace Avalonia.Styling
{
- internal class DescendentSelector : Selector
+ internal class DescendantSelector : Selector
{
private readonly Selector _parent;
private string _selectorString;
- public DescendentSelector(Selector parent)
+ public DescendantSelector(Selector parent)
{
if (parent == null)
{
- throw new InvalidOperationException("Descendent selector must be preceeded by a selector.");
+ throw new InvalidOperationException("Descendant selector must be preceeded by a selector.");
}
_parent = parent;
@@ -41,7 +41,7 @@ namespace Avalonia.Styling
protected override SelectorMatch Evaluate(IStyleable control, bool subscribe)
{
ILogical c = (ILogical)control;
- List> descendentMatches = new List>();
+ List> descendantMatches = new List>();
while (c != null)
{
@@ -60,14 +60,14 @@ namespace Avalonia.Styling
}
else
{
- descendentMatches.Add(match.ObservableResult);
+ descendantMatches.Add(match.ObservableResult);
}
}
}
- if (descendentMatches.Count > 0)
+ if (descendantMatches.Count > 0)
{
- return new SelectorMatch(StyleActivator.Or(descendentMatches));
+ return new SelectorMatch(StyleActivator.Or(descendantMatches));
}
else
{
diff --git a/src/Avalonia.Styling/Styling/Selectors.cs b/src/Avalonia.Styling/Styling/Selectors.cs
index 1b4c876f81..c91cc7af04 100644
--- a/src/Avalonia.Styling/Styling/Selectors.cs
+++ b/src/Avalonia.Styling/Styling/Selectors.cs
@@ -42,13 +42,13 @@ namespace Avalonia.Styling
}
///
- /// Returns a selector which matches a descendent of a previous selector.
+ /// Returns a selector which matches a descendant of a previous selector.
///
/// The previous selector.
/// The selector.
- public static Selector Descendent(this Selector previous)
+ public static Selector Descendant(this Selector previous)
{
- return new DescendentSelector(previous);
+ return new DescendantSelector(previous);
}
///
diff --git a/src/Avalonia.Styling/Styling/Style.cs b/src/Avalonia.Styling/Styling/Style.cs
index be4282cdc0..3dfd9118af 100644
--- a/src/Avalonia.Styling/Styling/Style.cs
+++ b/src/Avalonia.Styling/Styling/Style.cs
@@ -13,10 +13,10 @@ namespace Avalonia.Styling
///
public class Style : IStyle
{
- private static Dictionary> _applied =
+ private static Dictionary> _applied =
new Dictionary>();
- private Dictionary _resources;
+ private StyleResources _resources;
///
/// Initializes a new instance of the class.
@@ -37,13 +37,13 @@ namespace Avalonia.Styling
///
/// Gets or sets a dictionary of style resources.
///
- public IDictionary Resources
+ public StyleResources Resources
{
get
{
if (_resources == null)
{
- _resources = new Dictionary();
+ _resources = new StyleResources();
}
return _resources;
@@ -51,25 +51,30 @@ namespace Avalonia.Styling
set
{
+
var resources = Resources;
-
- foreach (var i in value)
+ if (!Equals(resources, value))
{
- resources.Add(i);
+ foreach (var i in value)
+ {
+ resources[i.Key] = i.Value;
+ //resources.Add(i.Key, i.Value);
+ //(resources as IDictionary).Add(i);
+ }
}
}
}
///
- /// Gets or sets style's selector.
+ /// Gets or sets the style's selector.
///
public Selector Selector { get; set; }
///
- /// Gets or sets style's setters.
+ /// Gets or sets the style's setters.
///
[Content]
- public IEnumerable Setters { get; set; } = new List();
+ public IList Setters { get; set; } = new List();
///
/// Attaches the style to a control if the style's selector matches.
diff --git a/src/Avalonia.Styling/Styling/StyleResources.cs b/src/Avalonia.Styling/Styling/StyleResources.cs
new file mode 100644
index 0000000000..e447c6adfd
--- /dev/null
+++ b/src/Avalonia.Styling/Styling/StyleResources.cs
@@ -0,0 +1,90 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Avalonia.Styling
+{
+ ///
+ /// Holds resources for a .
+ ///
+ public class StyleResources : IDictionary, IDictionary
+ {
+ private Dictionary _inner = new Dictionary();
+
+ public object this[string key]
+ {
+ get { return _inner[key]; }
+ set { _inner[key] = value; }
+ }
+
+ public int Count => _inner.Count;
+
+ ICollection IDictionary.Keys => _inner.Keys;
+
+ ICollection IDictionary.Values => _inner.Values;
+
+ bool ICollection>.IsReadOnly => false;
+
+ object IDictionary.this[object key]
+ {
+ get { return ((IDictionary)_inner)[key]; }
+ set { ((IDictionary)_inner)[key] = value; }
+ }
+
+ ICollection IDictionary.Keys => _inner.Keys;
+
+ ICollection IDictionary.Values => _inner.Values;
+
+ bool ICollection.IsSynchronized => false;
+
+ object ICollection.SyncRoot => ((IDictionary)_inner).SyncRoot;
+
+ bool IDictionary.IsFixedSize => false;
+
+ bool IDictionary.IsReadOnly => false;
+
+ public void Add(string key, object value) => _inner.Add(key, value);
+
+ public void Clear() => _inner.Clear();
+
+ public bool ContainsKey(string key) => _inner.ContainsKey(key);
+
+ public bool Remove(string key) => _inner.Remove(key);
+
+ public IEnumerator> GetEnumerator() => _inner.GetEnumerator();
+
+ public bool TryGetValue(string key, out object value) => _inner.TryGetValue(key, out value);
+
+ bool ICollection>.Contains(KeyValuePair item)
+ {
+ return ((IDictionary)_inner).Contains(item);
+ }
+
+ void ICollection>.Add(KeyValuePair item)
+ {
+ ((IDictionary)_inner).Add(item);
+ }
+
+ void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
+ {
+ ((IDictionary)_inner).CopyTo(array, arrayIndex);
+ }
+
+ bool ICollection>.Remove(KeyValuePair item)
+ {
+ return ((IDictionary)_inner).Remove(item);
+ }
+
+ void ICollection.CopyTo(Array array, int index) => ((IDictionary)_inner).CopyTo(array, index);
+
+ IEnumerator IEnumerable.GetEnumerator() => _inner.GetEnumerator();
+
+ IDictionaryEnumerator IDictionary.GetEnumerator() => ((IDictionary)_inner).GetEnumerator();
+
+ void IDictionary.Add(object key, object value) => ((IDictionary)_inner).Add(key, value);
+
+ bool IDictionary.Contains(object key) => ((IDictionary)_inner).Contains(key);
+
+ void IDictionary.Remove(object key) => ((IDictionary)_inner).Remove(key);
+ }
+}
diff --git a/src/Avalonia.Styling/packages.config b/src/Avalonia.Styling/packages.config
deleted file mode 100644
index 9f732f1bcb..0000000000
--- a/src/Avalonia.Styling/packages.config
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
index 38786f54d3..cb86598a42 100644
--- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
+++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
@@ -1,6 +1,5 @@
+";
+
+ var styles = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Equal(1, styles.Count);
+
+ var style = (Style)styles[0];
+
+ var setters = style.Setters.Cast().ToArray();
+
+ Assert.Equal(2, setters.Length);
+
+ Assert.Equal(TextBlock.BackgroundProperty, setters[0].Property);
+ Assert.Equal(Brushes.White.Color, ((ISolidColorBrush)setters[0].Value).Color);
+
+ Assert.Equal(TextBlock.WidthProperty, setters[1].Property);
+ Assert.Equal(100.0, setters[1].Value);
+ }
+
+ [Fact]
+ public void Style_Setter_With_AttachedProperty_Is_Parsed()
+ {
+ var xaml = @"
+
+
+";
+
+ var styles = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Equal(1, styles.Count);
+
+ var style = (Style)styles[0];
+
+ var setters = style.Setters.Cast().ToArray();
+
+ Assert.Equal(1, setters.Length);
+
+ Assert.Equal(TextBlock.FontSizeProperty, setters[0].Property);
+ Assert.Equal(21.0, setters[0].Value);
+ }
+
+ [Fact]
+ public void Complex_Style_Is_Parsed()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+
+";
+ var styles = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Equal(1, styles.Count);
+
+ var style = (Style)styles[0];
+
+ var setters = style.Setters.Cast().ToArray();
+
+ Assert.Equal(3, setters.Length);
+
+ Assert.Equal(CheckBox.BorderBrushProperty, setters[0].Property);
+ Assert.Equal(CheckBox.BorderThicknessProperty, setters[1].Property);
+ Assert.Equal(CheckBox.TemplateProperty, setters[2].Property);
+
+ Assert.IsType(setters[0].Value);
+ Assert.IsType(setters[1].Value);
+ Assert.IsType(setters[2].Value);
+ }
+ }
+
+ [Fact]
+ public void Style_Resources_Are_Built()
+ {
+ var xaml = @"
+";
+
+ var style = AvaloniaXamlLoader.Parse";
+
+ var styles = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.True(styles.Count == 1);
+
+ var styleInclude = styles.First() as StyleInclude;
+
+ Assert.NotNull(styleInclude);
+
+ var style = styleInclude.Loaded;
+
+ Assert.NotNull(style);
+ }
+ }
+
+ [Fact]
+ public void Simple_Xaml_Binding_Is_Operational()
+ {
+ using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
+ .With(windowingPlatform: new MockWindowingPlatform())))
+ {
+ var xaml =
+@"";
+
+ var target = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Null(target.Content);
+
+ target.DataContext = "Foo";
+
+ Assert.Equal("Foo", target.Content);
+ }
+ }
+
+ [Fact]
+ public void Xaml_Binding_Is_Delayed()
+ {
+ using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
+ {
+ var xaml =
+@"";
+
+ var target = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Null(target.Content);
+
+ target.DataContext = "Foo";
+
+ Assert.Null(target.Content);
+
+ DelayedBinding.ApplyBindings(target);
+
+ Assert.Equal("Foo", target.Content);
+ }
+ }
+
+ [Fact]
+ public void Double_Xaml_Binding_Is_Operational()
+ {
+ using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
+ .With(windowingPlatform: new MockWindowingPlatform())))
+ {
+ var xaml =
+@"";
+
+ var target = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Null(target.Content);
+
+ target.DataContext = 55.0;
+
+ Assert.Equal(55.0, target.Width);
+ }
+ }
+
+ [Fact]
+ public void Collection_Xaml_Binding_Is_Operational()
+ {
+ using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
+ .With(windowingPlatform: new MockWindowingPlatform())))
+ {
+ var xaml = @"
+
+
+
+
+";
+
+ var target = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.NotNull(target.Content);
+
+ var itemsControl = target.FindControl("itemsControl");
+
+ var items = new string[] { "Foo", "Bar" };
+
+ //DelayedBinding.ApplyBindings(itemsControl);
+
+ target.DataContext = items;
+
+ Assert.Equal(items, itemsControl.Items);
+ }
+ }
+
+ [Fact]
+ public void Multi_Xaml_Binding_Is_Parsed()
+ {
+ var xaml =
+@"
+
+
+";
+
+ var target = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.Equal(2, target.Bindings.Count);
+
+ Assert.Equal(BoolConverters.And, target.Converter);
+
+ var bindings = target.Bindings.Cast().ToArray();
+
+ Assert.Equal("Foo", bindings[0].Path);
+ Assert.Equal("Bar", bindings[1].Path);
+ }
+
+ [Fact]
+ public void Control_Template_Is_Operational()
+ {
+ using (UnitTestApplication.Start(TestServices.MockPlatformWrapper
+ .With(windowingPlatform: new MockWindowingPlatform())))
+ {
+ var xaml = @"
+
+
+
+
+
+
+";
+
+ var target = AvaloniaXamlLoader.Parse(xaml);
+
+ Assert.NotNull(target.Template);
+
+ Assert.Null(target.Presenter);
+
+ target.ApplyTemplate();
+
+ Assert.NotNull(target.Presenter);
+
+ target.Content = "Foo";
+
+ Assert.Equal("Foo", target.Presenter.Content);
+ }
+ }
+
+ [Fact]
+ public void Style_ControlTemplate_Is_Built()
+ {
+ var xaml = @"
+ ";
+
+ var style = AvaloniaXamlLoader.Parse
+
+
+";
+
+
+ var window = AvaloniaXamlLoader.Parse(xaml);
+ var tracker = (InitializationOrderTracker)window.Content;
+
+ //ensure binding is set and operational first
+ Assert.Equal(100.0, tracker.Tag);
+
+ Assert.Equal("EndInit 0", tracker.Order.Last());
+ }
+ }
+
+ [Fact]
+ public void BeginInit_Matches_EndInit()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+
+ var window = AvaloniaXamlLoader.Parse(xaml);
+ var tracker = (InitializationOrderTracker)window.Content;
+
+ Assert.Equal(0, tracker.InitState);
+ }
+ }
+
+ [Fact]
+ public void DeferedXamlLoader_Should_Preserve_NamespacesContext()
+ {
+ var xaml =
+@"
+
+
+
+
+
+";
+
+ var contentControl = AvaloniaXamlLoader.Parse(xaml);
+ var template = contentControl.ContentTemplate;
+
+ Assert.NotNull(template);
+
+ var txt = (TextBlock)template.Build(null);
+
+ Assert.Equal((object)NonControl.StringProperty, txt.Tag);
+ }
+
+ [Fact]
+ public void Binding_To_List_AvaloniaProperty_Is_Operational()
+ {
+ using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
+ {
+ var xaml = @"
+
+
+";
+
+ var window = AvaloniaXamlLoader.Parse(xaml);
+ var listBox = (ListBox)window.Content;
+
+ var vm = new SelectedItemsViewModel()
+ {
+ Items = new string[] { "foo", "bar", "baz" }
+ };
+
+ window.DataContext = vm;
+
+ Assert.Equal(vm.Items, listBox.Items);
+
+ Assert.Equal(vm.SelectedItems, listBox.SelectedItems);
+ }
+ }
+
+ private class SelectedItemsViewModel : INotifyPropertyChanged
+ {
+ public string[] Items { get; set; }
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ private IList _selectedItems = new AvaloniaList();
+
+ public IList SelectedItems
+ {
+ get { return _selectedItems; }
+ set
+ {
+ _selectedItems = value;
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedItems)));
+ }
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
index a66d6ac6d8..a44d09dee7 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests.cs
@@ -1,6 +1,7 @@
// 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.Reactive.Subjects;
using Avalonia.Controls;
using Avalonia.UnitTests;
using Xunit;
@@ -83,7 +84,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
[Fact]
public void Can_Bind_To_DataContext_Of_Anchor_On_Non_Control()
{
- using (UnitTestApplication.Start(TestServices.StyledWindow))
+ using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var xaml = @"
";
- var loader = new AvaloniaXamlLoader();
- var window = (Window)loader.Load(xaml);
+
+ var window = AvaloniaXamlLoader.Parse(xaml);
var textBlock = (TextBlock)window.Content;
- window.ApplyTemplate();
+ textBlock.Tag = "foo";
Assert.Equal("foo", textBlock.Text);
}
@@ -169,7 +171,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
[Fact]
public void Longform_Binding_To_Self_Works()
{
- using (UnitTestApplication.Start(TestServices.StyledWindow))
+ using (UnitTestApplication.Start(TestServices.MockWindowingPlatform))
{
var xaml = @"
+
+";
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var textBlock = (TextBlock)window.Content;
+ var observable = new BehaviorSubject("foo");
+
+ window.DataContext = new { Observable = observable };
+ window.ApplyTemplate();
+
+ Assert.Equal("foo", textBlock.Text);
+ observable.OnNext("bar");
+ Assert.Equal("bar", textBlock.Text);
+ }
+ }
}
-}
+}
\ No newline at end of file
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests_RelativeSource.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests_RelativeSource.cs
new file mode 100644
index 0000000000..9125e1e643
--- /dev/null
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BindingTests_RelativeSource.cs
@@ -0,0 +1,129 @@
+// 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 Avalonia.Controls;
+using Avalonia.UnitTests;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests.Xaml
+{
+ public class BindingTests_RelativeSource
+ {
+ [Fact]
+ public void Binding_To_DataContext_Works()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var button = window.FindControl