Browse Source

Merge remote-tracking branch 'origin/master' into pr/1123-clean-up-build-warnings

Steven Kirk 8 years ago
parent
commit
e06cdd8810
66 changed files with 483 additions and 340 deletions
  1. 1 1
      .gitignore
  2. 1 1
      build.cake
  3. 1 0
      samples/BindingTest/BindingTest.csproj
  4. 2 1
      samples/BindingTest/MainWindow.xaml
  5. 8 0
      samples/BindingTest/ViewModels/MainWindowViewModel.cs
  6. 20 0
      samples/BindingTest/ViewModels/NestedCommandViewModel.cs
  7. 1 0
      src/Avalonia.Base/Avalonia.Base.csproj
  8. 3 16
      src/Avalonia.Base/AvaloniaObject.cs
  9. 1 0
      src/Avalonia.Base/Data/BindingNotification.cs
  10. 53 0
      src/Avalonia.Base/Logging/LoggerExtensions.cs
  11. 1 1
      src/Avalonia.Base/PriorityBindingEntry.cs
  12. 1 8
      src/Avalonia.Base/PriorityValue.cs
  13. 0 23
      src/Avalonia.Base/Utilities/ExceptionUtilities.cs
  14. 9 6
      src/Avalonia.Controls/Application.cs
  15. 20 4
      src/Avalonia.Controls/Button.cs
  16. 10 12
      src/Avalonia.Controls/Control.cs
  17. 8 6
      src/Avalonia.Controls/IControl.cs
  18. 1 5
      src/Avalonia.Controls/IGlobalDataTemplates.cs
  19. 1 1
      src/Avalonia.Controls/MenuItem.cs
  20. 15 9
      src/Avalonia.Controls/Templates/DataTemplateExtensions.cs
  21. 27 0
      src/Avalonia.Controls/Templates/IDataTemplateHost.cs
  22. 1 1
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  23. 1 1
      src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
  24. 2 18
      src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj
  25. 11 2
      src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
  26. 3 0
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj
  27. 0 21
      src/Avalonia.DotNetFrameworkRuntime/Properties/AssemblyInfo.cs
  28. 12 8
      src/Avalonia.Interactivity/Interactive.cs
  29. 3 0
      src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj
  30. 0 27
      src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs
  31. 1 0
      src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj
  32. 0 24
      src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs
  33. 11 1
      src/Avalonia.Styling/Styling/IStyleHost.cs
  34. 7 4
      src/Avalonia.Styling/Styling/StyleExtensions.cs
  35. 4 1
      src/Avalonia.Styling/Styling/Styler.cs
  36. 2 0
      src/Avalonia.Visuals/Media/PathMarkupParser.cs
  37. 3 0
      src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj
  38. 0 20
      src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs
  39. 3 0
      src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj
  40. 0 13
      src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs
  41. 1 0
      src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj
  42. 2 0
      src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs
  43. 1 24
      src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs
  44. 1 11
      src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs
  45. 6 4
      src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs
  46. 1 1
      src/Shared/PlatformSupport/AssetLoader.cs
  47. 1 1
      src/Shared/PlatformSupport/StandardRuntimePlatform.cs
  48. 3 3
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
  49. 3 3
      tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs
  50. 125 0
      tests/Avalonia.Controls.UnitTests/ButtonTests.cs
  51. 1 1
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
  52. 4 4
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
  53. 1 1
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs
  54. 1 0
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  55. 4 4
      tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs
  56. 2 2
      tests/Avalonia.Controls.UnitTests/TabControlTests.cs
  57. 14 14
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  58. 1 1
      tests/Avalonia.Controls.UnitTests/UserControlTests.cs
  59. 5 1
      tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj
  60. 1 0
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
  61. 1 1
      tests/Avalonia.LeakTests/ControlTests.cs
  62. 39 16
      tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs
  63. 2 2
      tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs
  64. 1 1
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs
  65. 10 10
      tests/Avalonia.Styling.UnitTests/ResourceTests.cs
  66. 4 0
      tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs

+ 1 - 1
.gitignore

@@ -108,7 +108,7 @@ AppPackages/
 # NCrunch
 _NCrunch_*/
 *.ncrunchsolution.user
-nCrunchTemp_*/
+nCrunchTemp_*
 
 # Others
 sql/

+ 1 - 1
build.cake

@@ -6,7 +6,7 @@
 #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"
+#tool "nuget:?package=JetBrains.ReSharper.CommandLineTools&version=2017.1.20170613.162720"
 ///////////////////////////////////////////////////////////////////////////////
 // TOOLS
 ///////////////////////////////////////////////////////////////////////////////

+ 1 - 0
samples/BindingTest/BindingTest.csproj

@@ -66,6 +66,7 @@
     <Compile Include="ViewModels\IndeiErrorViewModel.cs" />
     <Compile Include="ViewModels\ExceptionErrorViewModel.cs" />
     <Compile Include="ViewModels\MainWindowViewModel.cs" />
+    <Compile Include="ViewModels\NestedCommandViewModel.cs" />
     <Compile Include="ViewModels\TestItem.cs" />
   </ItemGroup>
   <ItemGroup>

+ 2 - 1
samples/BindingTest/MainWindow.xaml

@@ -97,8 +97,9 @@
         <Button Content="Button" Command="{Binding StringValueCommand}" CommandParameter="Button"/>
         <ToggleButton Content="ToggleButton" IsChecked="{Binding BooleanFlag, Mode=OneWay}" Command="{Binding StringValueCommand}" CommandParameter="ToggleButton"/>
         <CheckBox Content="CheckBox" IsChecked="{Binding !BooleanFlag, Mode=OneWay}" Command="{Binding StringValueCommand}" CommandParameter="CheckBox"/>
-        <RadioButton Content="RadionButton" IsChecked="{Binding !!BooleanFlag, Mode=OneWay}" Command="{Binding StringValueCommand}" CommandParameter="RadioButton"/>
+        <RadioButton Content="Radio Button" IsChecked="{Binding !!BooleanFlag, Mode=OneWay}" Command="{Binding StringValueCommand}" CommandParameter="RadioButton"/>
         <TextBox Text="{Binding Path=StringValue}"/>
+        <Button Content="Nested View Model Button" Name="NestedTest" Command="{Binding NestedModel.Command}" />
       </StackPanel>
     </TabItem>
   </TabControl>

+ 8 - 0
samples/BindingTest/ViewModels/MainWindowViewModel.cs

@@ -15,6 +15,7 @@ namespace BindingTest.ViewModels
         private string _stringValue = "Simple Binding";
         private bool _booleanFlag = false;
         private string _currentTime;
+        private NestedCommandViewModel _nested;
 
         public MainWindowViewModel()
         {
@@ -39,6 +40,7 @@ namespace BindingTest.ViewModels
             {
                 BooleanFlag = !BooleanFlag;
                 StringValue = param.ToString();
+                NestedModel = _nested ?? new NestedCommandViewModel();
             });
 
             Task.Run(() =>
@@ -94,5 +96,11 @@ namespace BindingTest.ViewModels
         public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel();
         public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel();
         public IndeiErrorViewModel IndeiDataValidation { get; } = new IndeiErrorViewModel();
+
+        public NestedCommandViewModel NestedModel
+        {
+            get { return _nested; }
+            private set { this.RaiseAndSetIfChanged(ref _nested, value); }
+        }
     }
 }

+ 20 - 0
samples/BindingTest/ViewModels/NestedCommandViewModel.cs

@@ -0,0 +1,20 @@
+using ReactiveUI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace BindingTest.ViewModels
+{
+    public class NestedCommandViewModel : ReactiveObject
+    {
+        public NestedCommandViewModel()
+        {
+            Command = ReactiveCommand.Create();
+        }
+
+        public ICommand Command { get; }
+    }
+}

+ 1 - 0
src/Avalonia.Base/Avalonia.Base.csproj

@@ -2,6 +2,7 @@
   <PropertyGroup>
     <TargetFramework>netstandard1.3</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <RootNamespace>Avalonia</RootNamespace>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
     <DebugSymbols>true</DebugSymbols>

+ 3 - 16
src/Avalonia.Base/AvaloniaObject.cs

@@ -664,24 +664,11 @@ namespace Avalonia
 
             if (notification != null)
             {
-                if (notification.ErrorType == BindingErrorType.Error)
-                {
-                    Logger.Error(
-                        LogArea.Binding,
-                        this,
-                        "Error in binding to {Target}.{Property}: {Message}",
-                        this,
-                        property,
-                        ExceptionUtilities.GetMessage(notification.Error));
-                }
-
-                if (notification.HasValue)
-                {
-                    value = notification.Value;
-                }
+                notification.LogIfError(this, property);
+                value = notification.Value;
             }
 
-            if (notification == null || notification.HasValue)
+            if (notification == null || notification.ErrorType == BindingErrorType.Error || notification.HasValue)
             {
                 var metadata = (IDirectPropertyMetadata)property.GetMetadata(GetType());
                 var accessor = (IDirectPropertyAccessor)GetRegistered(property);

+ 1 - 0
src/Avalonia.Base/Data/BindingNotification.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 Avalonia.Logging;
 
 namespace Avalonia.Data
 {

+ 53 - 0
src/Avalonia.Base/Logging/LoggerExtensions.cs

@@ -0,0 +1,53 @@
+using System;
+using Avalonia.Data;
+
+namespace Avalonia.Logging
+{
+    internal static class LoggerExtensions
+    {
+        public static void LogIfError(
+            this BindingNotification notification,
+            object source,
+            AvaloniaProperty property)
+        {
+            if (notification.ErrorType == BindingErrorType.Error)
+            {
+                if (notification.Error is AggregateException aggregate)
+                {
+                    foreach (var inner in aggregate.InnerExceptions)
+                    {
+                        LogError(source, property, inner);
+                    }
+                }
+                else
+                {
+                    LogError(source, property, notification.Error);
+                }
+            }
+        }
+
+        private static void LogError(object source, AvaloniaProperty property, Exception e)
+        {
+            var level = LogEventLevel.Warning;
+
+            if (e is BindingChainException b &&
+                !string.IsNullOrEmpty(b.Expression) &&
+                string.IsNullOrEmpty(b.ExpressionErrorPoint))
+            {
+                // The error occurred at the root of the binding chain: it's possible that the
+                // DataContext isn't set up yet, so log at Information level instead of Warning
+                // to prevent spewing hundreds of errors.
+                level = LogEventLevel.Information;
+            }
+
+            Logger.Log(
+                level,
+                LogArea.Binding,
+                source,
+                "Error in binding to {Target}.{Property}: {Message}",
+                source,
+                property,
+                e.Message);
+        }
+    }
+}

+ 1 - 1
src/Avalonia.Base/PriorityBindingEntry.cs

@@ -98,7 +98,7 @@ namespace Avalonia
 
             if (notification != null)
             {
-                if (notification.HasValue)
+                if (notification.HasValue || notification.ErrorType == BindingErrorType.Error)
                 {
                     Value = notification.Value;
                     _owner.Changed(this);

+ 1 - 8
src/Avalonia.Base/PriorityValue.cs

@@ -189,14 +189,7 @@ namespace Avalonia
         /// <param name="error">The binding error.</param>
         public void LevelError(PriorityLevel level, BindingNotification error)
         {
-            Logger.Log(
-                LogEventLevel.Error,
-                LogArea.Binding,
-                Owner,
-                "Error in binding to {Target}.{Property}: {Message}",
-                Owner,
-                Property,
-                error.Error.Message);
+            error.LogIfError(Owner, Property);
         }
 
         /// <summary>

+ 0 - 23
src/Avalonia.Base/Utilities/ExceptionUtilities.cs

@@ -1,23 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Avalonia.Utilities
-{
-    internal static class ExceptionUtilities
-    {
-        public static string GetMessage(Exception e)
-        {
-            var aggregate = e as AggregateException;
-
-            if (aggregate != null)
-            {
-                return string.Join(" | ", aggregate.InnerExceptions.Select(x => x.Message));
-            }
-
-            return e.Message;
-        }
-    }
-}

+ 9 - 6
src/Avalonia.Controls/Application.cs

@@ -39,6 +39,7 @@ namespace Avalonia
         private readonly Lazy<IClipboard> _clipboard =
             new Lazy<IClipboard>(() => (IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)));
         private readonly Styler _styler = new Styler();
+        private Styles _styles;
 
         /// <summary>
         /// Initializes a new instance of the <see cref="Application"/> class.
@@ -65,11 +66,7 @@ namespace Avalonia
         /// <value>
         /// The application's global data templates.
         /// </value>
-        public DataTemplates DataTemplates
-        {
-            get { return _dataTemplates ?? (_dataTemplates = new DataTemplates()); }
-            set { _dataTemplates = value; }
-        }
+        public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates());
 
         /// <summary>
         /// Gets the application's focus manager.
@@ -109,13 +106,19 @@ namespace Avalonia
         /// <remarks>
         /// Global styles apply to all windows in the application.
         /// </remarks>
-        public Styles Styles { get; } = new Styles();
+        public Styles Styles => _styles ?? (_styles = new Styles());
+
+        /// <inheritdoc/>
+        bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;
 
         /// <summary>
         /// Gets the styling parent of the application, which is null.
         /// </summary>
         IStyleHost IStyleHost.StylingParent => null;
 
+        /// <inheritdoc/>
+        bool IStyleHost.IsStylesInitialized => _styles != null;
+
         /// <summary>
         /// Initializes the application by loading XAML etc.
         /// </summary>

+ 20 - 4
src/Avalonia.Controls/Button.cs

@@ -4,6 +4,7 @@
 using System;
 using System.Linq;
 using System.Windows.Input;
+using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Interactivity;
 using Avalonia.Rendering;
@@ -41,8 +42,9 @@ namespace Avalonia.Controls
         /// <summary>
         /// Defines the <see cref="Command"/> property.
         /// </summary>
-        public static readonly StyledProperty<ICommand> CommandProperty =
-            AvaloniaProperty.Register<Button, ICommand>(nameof(Command));
+        public static readonly DirectProperty<Button, ICommand> CommandProperty =
+            AvaloniaProperty.RegisterDirect<Button, ICommand>(nameof(Command),
+                button => button.Command, (button, command) => button.Command = command, enableDataValidation: true);
 
         /// <summary>
         /// Defines the <see cref="HotKey"/> property.
@@ -68,6 +70,8 @@ namespace Avalonia.Controls
         public static readonly RoutedEvent<RoutedEventArgs> ClickEvent =
             RoutedEvent.Register<Button, RoutedEventArgs>("Click", RoutingStrategies.Bubble);
 
+        private ICommand _command;
+
         /// <summary>
         /// Initializes static members of the <see cref="Button"/> class.
         /// </summary>
@@ -102,8 +106,8 @@ namespace Avalonia.Controls
         /// </summary>
         public ICommand Command
         {
-            get { return GetValue(CommandProperty); }
-            set { SetValue(CommandProperty, value); }
+            get { return _command; }
+            set { SetAndRaise(CommandProperty, ref _command, value); }
         }
 
         /// <summary>
@@ -250,6 +254,18 @@ namespace Avalonia.Controls
             }
         }
 
+        protected override void UpdateDataValidation(AvaloniaProperty property, BindingNotification status)
+        {
+            base.UpdateDataValidation(property, status);
+            if(property == CommandProperty)
+            {
+                if(status?.ErrorType == BindingErrorType.Error)
+                {
+                    IsEnabled = false;
+                }
+            }
+        }
+
         /// <summary>
         /// Called when the <see cref="Command"/> property changes.
         /// </summary>

+ 10 - 12
src/Avalonia.Controls/Control.cs

@@ -97,8 +97,8 @@ namespace Avalonia.Controls
         private bool _isAttachedToLogicalTree;
         private IAvaloniaList<ILogical> _logicalChildren;
         private INameScope _nameScope;
-        private Styles _styles;
         private bool _styled;
+        private Styles _styles;
         private Subject<IStyleable> _styleDetach = new Subject<IStyleable>();
 
         /// <summary>
@@ -243,11 +243,7 @@ namespace Avalonia.Controls
         /// Each control may define data templates which are applied to the control itself and its
         /// children.
         /// </remarks>
-        public DataTemplates DataTemplates
-        {
-            get { return _dataTemplates ?? (_dataTemplates = new DataTemplates()); }
-            set { _dataTemplates = value; }
-        }
+        public DataTemplates DataTemplates => _dataTemplates ?? (_dataTemplates = new DataTemplates());
 
         /// <summary>
         /// Gets a value that indicates whether the element has finished initialization.
@@ -259,18 +255,14 @@ namespace Avalonia.Controls
         public bool IsInitialized { get; private set; }
 
         /// <summary>
-        /// Gets or sets the styles for the control.
+        /// Gets the styles for the control.
         /// </summary>
         /// <remarks>
         /// Styles for the entire application are added to the Application.Styles collection, but
         /// each control may in addition define its own styles which are applied to the control
         /// itself and its children.
         /// </remarks>
-        public Styles Styles
-        {
-            get { return _styles ?? (_styles = new Styles()); }
-            set { _styles = value; }
-        }
+        public Styles Styles => _styles ?? (_styles = new Styles());
 
         /// <summary>
         /// Gets the control's logical parent.
@@ -304,6 +296,9 @@ namespace Avalonia.Controls
             internal set { SetValue(TemplatedParentProperty, value); }
         }
 
+        /// <inheritdoc/>
+        bool IDataTemplateHost.IsDataTemplatesInitialized => _dataTemplates != null;
+
         /// <summary>
         /// Gets a value indicating whether the element is attached to a rooted logical tree.
         /// </summary>
@@ -336,6 +331,9 @@ namespace Avalonia.Controls
         /// <inheritdoc/>
         IObservable<IStyleable> IStyleable.StyleDetach => _styleDetach;
 
+        /// <inheritdoc/>
+        bool IStyleHost.IsStylesInitialized => _styles != null;
+
         /// <inheritdoc/>
         IStyleHost IStyleHost.StylingParent => (IStyleHost)InheritanceParent;
 

+ 8 - 6
src/Avalonia.Controls/IControl.cs

@@ -14,7 +14,14 @@ namespace Avalonia.Controls
     /// <summary>
     /// Interface for Avalonia controls.
     /// </summary>
-    public interface IControl : IVisual, ILogical, ILayoutable, IInputElement, INamed, IStyleable, IStyleHost
+    public interface IControl : IVisual,
+        IDataTemplateHost,
+        ILogical,
+        ILayoutable,
+        IInputElement,
+        INamed,
+        IStyleable,
+        IStyleHost
     {
         /// <summary>
         /// Occurs when the control has finished initialization.
@@ -31,11 +38,6 @@ namespace Avalonia.Controls
         /// </summary>
         object DataContext { get; set; }
 
-        /// <summary>
-        /// Gets the data templates for the control.
-        /// </summary>
-        DataTemplates DataTemplates { get; }
-
         /// <summary>
         /// Gets a value that indicates whether the element has finished initialization.
         /// </summary>

+ 1 - 5
src/Avalonia.Controls/IGlobalDataTemplates.cs

@@ -8,11 +8,7 @@ namespace Avalonia.Controls
     /// <summary>
     /// Defines the application-global data templates.
     /// </summary>
-    public interface IGlobalDataTemplates
+    public interface IGlobalDataTemplates : IDataTemplateHost
     {
-        /// <summary>
-        /// Gets the application-global data templates.
-        /// </summary>
-        DataTemplates DataTemplates { get; }
     }
 }

+ 1 - 1
src/Avalonia.Controls/MenuItem.cs

@@ -24,7 +24,7 @@ namespace Avalonia.Controls
         /// Defines the <see cref="Command"/> property.
         /// </summary>
         public static readonly StyledProperty<ICommand> CommandProperty =
-            Button.CommandProperty.AddOwner<MenuItem>();
+            AvaloniaProperty.Register<MenuItem, ICommand>(nameof(Command));
 
         /// <summary>
         /// Defines the <see cref="HotKey"/> property.

+ 15 - 9
src/Avalonia.Controls/Templates/DataTemplateExtensions.cs

@@ -17,8 +17,8 @@ namespace Avalonia.Controls.Templates
         /// <param name="control">The control searching for the data template.</param>
         /// <param name="data">The data.</param>
         /// <param name="primary">
-        /// An optional primary template that can will be tried before the
-        /// <see cref="IControl.DataTemplates"/> in the tree are searched.
+        /// An optional primary template that can will be tried before the DataTemplates in the
+        /// tree are searched.
         /// </param>
         /// <returns>The data template or null if no matching data template was found.</returns>
         public static IDataTemplate FindDataTemplate(
@@ -31,13 +31,16 @@ namespace Avalonia.Controls.Templates
                 return primary;
             }
 
-            foreach (var i in control.GetSelfAndLogicalAncestors().OfType<IControl>())
+            foreach (var i in control.GetSelfAndLogicalAncestors().OfType<IDataTemplateHost>())
             {
-                foreach (IDataTemplate dt in i.DataTemplates)
+                if (i.IsDataTemplatesInitialized)
                 {
-                    if (dt.Match(data))
+                    foreach (IDataTemplate dt in i.DataTemplates)
                     {
-                        return dt;
+                        if (dt.Match(data))
+                        {
+                            return dt;
+                        }
                     }
                 }
             }
@@ -46,11 +49,14 @@ namespace Avalonia.Controls.Templates
 
             if (global != null)
             {
-                foreach (IDataTemplate dt in global.DataTemplates)
+                if (global.IsDataTemplatesInitialized)
                 {
-                    if (dt.Match(data))
+                    foreach (IDataTemplate dt in global.DataTemplates)
                     {
-                        return dt;
+                        if (dt.Match(data))
+                        {
+                            return dt;
+                        }
                     }
                 }
             }

+ 27 - 0
src/Avalonia.Controls/Templates/IDataTemplateHost.cs

@@ -0,0 +1,27 @@
+// 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.Controls.Templates
+{
+    /// <summary>
+    /// Defines an element that has a <see cref="DataTemplates"/> collection.
+    /// </summary>
+    public interface IDataTemplateHost
+    {
+        /// <summary>
+        /// Gets the data templates for the element.
+        /// </summary>
+        DataTemplates DataTemplates { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="DataTemplates"/> is initialized.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="DataTemplates"/> property may be lazily initialized, if so this property
+        /// indicates whether it has been initialized.
+        /// </remarks>
+        bool IsDataTemplatesInitialized { get; }
+    }
+}

+ 1 - 1
src/Avalonia.Diagnostics/DevTools.xaml.cs

@@ -71,7 +71,7 @@ namespace Avalonia.Diagnostics
                         Width = 1024,
                         Height = 512,
                         Content = devTools,
-                        DataTemplates = new DataTemplates
+                        DataTemplates =
                         {
                             new ViewLocator<ViewModelBase>(),
                         }

+ 1 - 1
src/Avalonia.Diagnostics/Views/ControlDetailsView.cs

@@ -42,7 +42,7 @@ namespace Avalonia.Diagnostics.Views
             {
                 Content = _grid = new SimpleGrid
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.Is<Control>())
                         {

+ 2 - 18
src/Avalonia.DotNetCoreRuntime/Avalonia.DotNetCoreRuntime.csproj

@@ -3,24 +3,8 @@
     <TargetFramework>netcoreapp1.0</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>TRACE;DEBUG;NETSTANDARD</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Debug\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE;NETSTANDARD</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Release\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
+  <PropertyGroup>
+    <DocumentationFile>bin\$(Configuration)\Avalonia.DotNetCoreRuntime.XML</DocumentationFile>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="..\Shared\SharedAssemblyInfo.cs">

+ 11 - 2
src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs

@@ -59,7 +59,11 @@ namespace Avalonia
                                                from attribute in assembly.GetCustomAttributes<ExportWindowingSubsystemAttribute>()
                                                where attribute.RequiredOS == os && CheckEnvironment(attribute.EnvironmentChecker)
                                                orderby attribute.Priority ascending
-                                               select attribute).First();
+                                               select attribute).FirstOrDefault();
+            if (windowingSubsystemAttribute == null)
+            {
+                throw new InvalidOperationException("No windowing subsystem found. Are you missing assembly references?");
+            }
 
             var renderingSubsystemAttribute = (from assembly in RuntimePlatform.GetLoadedAssemblies()
                                                from attribute in assembly.GetCustomAttributes<ExportRenderingSubsystemAttribute>()
@@ -67,7 +71,12 @@ namespace Avalonia
                                                where attribute.RequiresWindowingSubsystem == null
                                                 || attribute.RequiresWindowingSubsystem == windowingSubsystemAttribute.Name
                                                orderby attribute.Priority ascending
-                                               select attribute).First();
+                                               select attribute).FirstOrDefault();
+
+            if (renderingSubsystemAttribute == null)
+            {
+                throw new InvalidOperationException("No rendering subsystem found. Are you missing assembly references?");
+            }
 
             UseWindowingSubsystem(() => windowingSubsystemAttribute.InitializationType
                 .GetRuntimeMethod(windowingSubsystemAttribute.InitializationMethod, Type.EmptyTypes).Invoke(null, null),

+ 3 - 0
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.csproj

@@ -44,6 +44,9 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Shared\SharedAssemblyInfo.cs">
+      <Link>Properties\SharedAssemblyInfo.cs</Link>
+    </Compile>
     <Compile Include="AppBuilder.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="RuntimeInfo.cs" />

+ 0 - 21
src/Avalonia.DotNetFrameworkRuntime/Properties/AssemblyInfo.cs

@@ -1,18 +1,10 @@
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following 
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("Avalonia.DotNetFrameworkRuntime")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Avalonia.DotNetFrameworkRuntime")]
-[assembly: AssemblyCopyright("Copyright ©  2016")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
 
 // Setting ComVisible to false makes the types in this assembly not visible 
 // to COM components.  If you need to access a type in this assembly from 
@@ -21,16 +13,3 @@ using System.Runtime.InteropServices;
 
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("4a1abb09-9047-4bd5-a4ad-a055e52c5ee0")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 12 - 8
src/Avalonia.Interactivity/Interactive.cs

@@ -16,14 +16,18 @@ namespace Avalonia.Interactivity
     /// </summary>
     public class Interactive : Layoutable, IInteractive
     {
-        private readonly Dictionary<RoutedEvent, List<EventSubscription>> _eventHandlers =
-            new Dictionary<RoutedEvent, List<EventSubscription>>();
+        private Dictionary<RoutedEvent, List<EventSubscription>> _eventHandlers;
 
         /// <summary>
         /// Gets the interactive parent of the object for bubbling and tunnelling events.
         /// </summary>
         IInteractive IInteractive.InteractiveParent => ((IVisual)this).VisualParent as IInteractive;
 
+        private Dictionary<RoutedEvent, List<EventSubscription>> EventHandlers
+        {
+            get { return _eventHandlers ?? (_eventHandlers = new Dictionary<RoutedEvent, List<EventSubscription>>()); }
+        }
+
         /// <summary>
         /// Adds a handler for the specified routed event.
         /// </summary>
@@ -43,10 +47,10 @@ namespace Avalonia.Interactivity
 
             List<EventSubscription> subscriptions;
 
-            if (!_eventHandlers.TryGetValue(routedEvent, out subscriptions))
+            if (!EventHandlers.TryGetValue(routedEvent, out subscriptions))
             {
                 subscriptions = new List<EventSubscription>();
-                _eventHandlers.Add(routedEvent, subscriptions);
+                EventHandlers.Add(routedEvent, subscriptions);
             }
 
             var sub = new EventSubscription
@@ -89,9 +93,9 @@ namespace Avalonia.Interactivity
             Contract.Requires<ArgumentNullException>(routedEvent != null);
             Contract.Requires<ArgumentNullException>(handler != null);
 
-            List<EventSubscription> subscriptions;
+            List<EventSubscription> subscriptions = null;
 
-            if (_eventHandlers.TryGetValue(routedEvent, out subscriptions))
+            if (_eventHandlers?.TryGetValue(routedEvent, out subscriptions) == true)
             {
                 subscriptions.RemoveAll(x => x.Handler == handler);
             }
@@ -181,9 +185,9 @@ namespace Avalonia.Interactivity
 
             e.RoutedEvent.InvokeRaised(this, e);
 
-            List<EventSubscription> subscriptions;
+            List<EventSubscription> subscriptions = null;
 
-            if (_eventHandlers.TryGetValue(e.RoutedEvent, out subscriptions))
+            if (_eventHandlers?.TryGetValue(e.RoutedEvent, out subscriptions) == true)
             {
                 foreach (var sub in subscriptions.ToList())
                 {

+ 3 - 0
src/Avalonia.Logging.Serilog/Avalonia.Logging.Serilog.csproj

@@ -23,6 +23,9 @@
     <DocumentationFile>bin\Release\Avalonia.Logging.Serilog.XML</DocumentationFile>
     <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
   </PropertyGroup>
+  <ItemGroup>
+    <Compile Include="..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
+  </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Avalonia.Base\Avalonia.Base.csproj" />
   </ItemGroup>

+ 0 - 27
src/Avalonia.Logging.Serilog/Properties/AssemblyInfo.cs

@@ -1,30 +1,3 @@
-using System.Resources;
 using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
 
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
 [assembly: AssemblyTitle("Avalonia.Serilog")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Avalonia.Serilog")]
-[assembly: AssemblyCopyright("Copyright ©  2016")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: NeutralResourcesLanguage("en")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 1 - 0
src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj

@@ -25,6 +25,7 @@
     <None Remove="Shims.cs" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>

+ 0 - 24
src/Avalonia.ReactiveUI/Properties/AssemblyInfo.cs

@@ -1,33 +1,9 @@
 // Copyright (c) The Avalonia Project. All rights reserved.
 // Licensed under the MIT license. See licence.md file in the project root for full license information.
 
-using System.Resources;
 using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following 
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("Avalonia.ReactiveUI")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Avalonia.ReactiveUI")]
-[assembly: AssemblyCopyright("Copyright \u00A9  2015")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: NeutralResourcesLanguage("en")]
-
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 11 - 1
src/Avalonia.Styling/Styling/IStyleHost.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 System;
+
 namespace Avalonia.Styling
 {
     /// <summary>
@@ -8,6 +10,15 @@ namespace Avalonia.Styling
     /// </summary>
     public interface IStyleHost
     {
+        /// <summary>
+        /// Gets a value indicating whether <see cref="Styles"/> is initialized.
+        /// </summary>
+        /// <remarks>
+        /// The <see cref="Styles"/> property may be lazily initialized, if so this property
+        /// indicates whether it has been initialized.
+        /// </remarks>
+        bool IsStylesInitialized { get; }
+
         /// <summary>
         /// Gets the styles for the element.
         /// </summary>
@@ -17,6 +28,5 @@ namespace Avalonia.Styling
         /// Gets the parent style host element.
         /// </summary>
         IStyleHost StylingParent { get; }
-
     }
 }

+ 7 - 4
src/Avalonia.Styling/Styling/StyleExtensions.cs

@@ -23,11 +23,14 @@ namespace Avalonia.Styling
 
             while (control != null)
             {
-                var result = control.Styles.FindResource(name);
-
-                if (result != AvaloniaProperty.UnsetValue)
+                if (control.IsStylesInitialized)
                 {
-                    return result;
+                    var result = control.Styles.FindResource(name);
+
+                    if (result != AvaloniaProperty.UnsetValue)
+                    {
+                        return result;
+                    }
                 }
 
                 control = control.StylingParent;

+ 4 - 1
src/Avalonia.Styling/Styling/Styler.cs

@@ -29,7 +29,10 @@ namespace Avalonia.Styling
                 ApplyStyles(control, parentContainer);
             }
 
-            styleHost.Styles.Attach(control, styleHost);
+            if (styleHost.IsStylesInitialized)
+            {
+                styleHost.Styles.Attach(control, styleHost);
+            }
         }
     }
 }

+ 2 - 0
src/Avalonia.Visuals/Media/PathMarkupParser.cs

@@ -126,7 +126,9 @@ namespace Avalonia.Media
                         case Command.CubicBezierCurve:
                             {
                                 Point point1 = ReadPoint(reader, point, relative);
+                                ReadSeparator(reader);
                                 Point point2 = ReadPoint(reader, point, relative);
+                                ReadSeparator(reader);
                                 point = ReadPoint(reader, point, relative);
                                 _context.CubicBezierTo(point1, point2, point);
                                 break;

+ 3 - 0
src/Gtk/Avalonia.Cairo/Avalonia.Cairo.csproj

@@ -47,6 +47,9 @@
     <Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
+      <Link>Properties\SharedAssemblyInfo.cs</Link>
+    </Compile>
     <Compile Include="CairoPlatform.cs" />
     <Compile Include="Media\DrawingContext.cs" />
     <Compile Include="Media\FormattedTextImpl.cs" />

+ 0 - 20
src/Gtk/Avalonia.Cairo/Properties/AssemblyInfo.cs

@@ -11,13 +11,6 @@ using System.Runtime.InteropServices;
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("Avalonia.Cairo")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Avalonia.Cairo")]
-[assembly: AssemblyCopyright("Copyright \u00A9  2014")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
 
 // Setting ComVisible to false makes the types in this assembly not visible 
 // to COM components.  If you need to access a type in this assembly from 
@@ -27,19 +20,6 @@ using System.Runtime.InteropServices;
 // The following GUID is for the ID of the typelib if this project is exposed to COM
 [assembly: Guid("f999ba8b-64e7-40cc-98a4-003f1852d2a3")]
 
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
-
 [assembly: ExportRenderingSubsystem(OperatingSystemType.WinNT, 3, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
 [assembly: ExportRenderingSubsystem(OperatingSystemType.Linux, 2, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]
 [assembly: ExportRenderingSubsystem(OperatingSystemType.OSX, 3, "Cairo", typeof(CairoPlatform), nameof(CairoPlatform.Initialize), RequiresWindowingSubsystem = "GTK")]

+ 3 - 0
src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj

@@ -39,6 +39,9 @@
     <Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="..\..\Shared\SharedAssemblyInfo.cs">
+      <Link>Properties\SharedAssemblyInfo.cs</Link>
+    </Compile>
     <Compile Include="ClipboardImpl.cs" />
     <Compile Include="EmbeddableImpl.cs" />
     <Compile Include="Embedding\GtkAvaloniaControlHost.cs" />

+ 0 - 13
src/Gtk/Avalonia.Gtk/Properties/AssemblyInfo.cs

@@ -4,23 +4,10 @@
 using Avalonia.Gtk;
 using Avalonia.Platform;
 using System.Reflection;
-using System.Runtime.CompilerServices;
 
 // Information about this assembly is defined by the following attributes.
 // Change them to the values specific to your project.
 [assembly: AssemblyTitle("Avalonia.Gtk")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("")]
-[assembly: AssemblyCopyright("steven")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
-// The form "{Major}.{Minor}.*" will automatically update the build and revision,
-// and "{Major}.{Minor}.{Build}.*" will update just the revision.
-[assembly: AssemblyVersion("1.0.*")]
 
 [assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 3, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]
 [assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 2, "GTK", typeof(GtkPlatform), nameof(GtkPlatform.Initialize))]

+ 1 - 0
src/Gtk/Avalonia.Gtk3/Avalonia.Gtk3.csproj

@@ -24,6 +24,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   <ItemGroup>
+    <Compile Include="..\..\Shared\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
     <Compile Include="..\Avalonia.Gtk\KeyTransform.cs">
       <Link>KeyTransform.cs</Link>
     </Compile>

+ 2 - 0
src/Gtk/Avalonia.Gtk3/Interop/Utf8Buffer.cs

@@ -36,6 +36,8 @@ namespace Avalonia.Gtk3.Interop
         public static unsafe string StringFromPtr(IntPtr s)
         {
             var pstr = (byte*)s;
+            if (pstr == null)
+                return null;
             int len;
             for (len = 0; pstr[len] != 0; len++) ;
             var bytes = new byte[len];

+ 1 - 24
src/Gtk/Avalonia.Gtk3/Properties/AssemblyInfo.cs

@@ -1,7 +1,4 @@
-using System.Resources;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
+using System.Reflection;
 using Avalonia.Gtk3;
 using Avalonia.Platform;
 
@@ -9,27 +6,7 @@ using Avalonia.Platform;
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("Avalonia.Gtk3")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("Avalonia.Gtk3")]
-[assembly: AssemblyCopyright("Copyright ©  2016")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-[assembly: NeutralResourcesLanguage("en")]
 
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers 
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
 [assembly: ExportWindowingSubsystem(OperatingSystemType.WinNT, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
 [assembly: ExportWindowingSubsystem(OperatingSystemType.Linux, 1, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]
 [assembly: ExportWindowingSubsystem(OperatingSystemType.OSX, 2, "GTK3", typeof(Gtk3Platform), nameof(Gtk3Platform.Initialize))]

+ 1 - 11
src/Markup/Avalonia.Markup/Data/ExpressionObserver.cs

@@ -239,17 +239,7 @@ namespace Avalonia.Markup.Data
 
                 if (broken != null)
                 {
-                    // We've received notification of a broken expression due to a null value
-                    // somewhere in the chain. If this null value occurs at the first node then we
-                    // ignore it, as its likely that e.g. the DataContext has not yet been set up.
-                    if (broken.HasNodes)
-                    {
-                        broken.Commit(Description);
-                    }
-                    else
-                    {
-                        o = AvaloniaProperty.UnsetValue;
-                    }
+                    broken.Commit(Description);
                 }
                 return o;
             }

+ 6 - 4
src/Markup/Avalonia.Markup/Data/MarkupBindingChainException.cs

@@ -32,10 +32,12 @@ namespace Avalonia.Markup.Data
         public void Commit(string expression)
         {
             Expression = expression;
-            ExpressionErrorPoint = string.Join(".", _nodes.Reverse())
-                .Replace(".!", "!")
-                .Replace(".[", "[")
-                .Replace(".^", "^");
+            ExpressionErrorPoint = _nodes != null ?
+                string.Join(".", _nodes.Reverse())
+                    .Replace(".!", "!")
+                    .Replace(".[", "[")
+                    .Replace(".^", "^") :
+                string.Empty;
             _nodes = null;
         }
     }

+ 1 - 1
src/Shared/PlatformSupport/AssetLoader.cs

@@ -137,7 +137,7 @@ namespace Avalonia.Shared.PlatformSupport
                 {
                     // iOS does not support loading assemblies dynamically!
                     //
-#if NETSTANDARD
+#if NETCOREAPP1_0
                     AssemblyNameCache[name] = rv = new AssemblyDescriptor(Assembly.Load(new AssemblyName(name)));
 #elif __IOS__
                     throw new InvalidOperationException(

+ 1 - 1
src/Shared/PlatformSupport/StandardRuntimePlatform.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Shared.PlatformSupport
     internal partial class StandardRuntimePlatform : IRuntimePlatform
     {
 
-#if NETSTANDARD
+#if NETCOREAPP1_0
         public void PostThreadPoolItem(Action cb) =>  ThreadPool.QueueUserWorkItem(_ => cb(), null);
 #else
         public Assembly[] GetLoadedAssemblies() => AppDomain.CurrentDomain.GetAssemblies();

+ 3 - 3
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs

@@ -314,7 +314,7 @@ namespace Avalonia.Base.UnitTests
                 new InvalidOperationException("Foo"),
                 BindingErrorType.Error));
 
-            Assert.Equal(6.7, target.GetValue(Class1.QuxProperty));
+            Assert.Equal(5.6, target.GetValue(Class1.QuxProperty));
         }
 
         [Fact]
@@ -343,7 +343,7 @@ namespace Avalonia.Base.UnitTests
 
             LogCallback checkLogMessage = (level, area, src, mt, pv) =>
             {
-                if (level == LogEventLevel.Error &&
+                if (level == LogEventLevel.Warning &&
                     area == LogArea.Binding &&
                     mt == expectedMessageTemplate)
                 {
@@ -359,7 +359,7 @@ namespace Avalonia.Base.UnitTests
                     new InvalidOperationException("Foo"),
                     BindingErrorType.Error));
 
-                Assert.Equal(6.7, target.GetValue(Class1.QuxProperty));
+                Assert.Equal(5.6, target.GetValue(Class1.QuxProperty));
                 Assert.True(called);
             }
         }

+ 3 - 3
tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Direct.cs

@@ -352,14 +352,14 @@ namespace Avalonia.Base.UnitTests
         }
 
         [Fact]
-        public void BindingError_Does_Not_Cause_Target_Update()
+        public void DataValidationError_Does_Not_Cause_Target_Update()
         {
             var target = new Class1();
             var source = new Subject<object>();
 
             target.Bind(Class1.FooProperty, source);
             source.OnNext("initial");
-            source.OnNext(new BindingNotification(new InvalidOperationException("Foo"), BindingErrorType.Error));
+            source.OnNext(new BindingNotification(new InvalidOperationException("Foo"), BindingErrorType.DataValidationError));
 
             Assert.Equal("initial", target.GetValue(Class1.FooProperty));
         }
@@ -389,7 +389,7 @@ namespace Avalonia.Base.UnitTests
 
             LogCallback checkLogMessage = (level, area, src, mt, pv) =>
             {
-                if (level == LogEventLevel.Error &&
+                if (level == LogEventLevel.Warning &&
                     area == LogArea.Binding &&
                     mt == "Error in binding to {Target}.{Property}: {Message}" &&
                     pv.Length == 3 &&

+ 125 - 0
tests/Avalonia.Controls.UnitTests/ButtonTests.cs

@@ -0,0 +1,125 @@
+using System;
+using System.Windows.Input;
+using Avalonia.Markup.Xaml.Data;
+using Xunit;
+
+namespace Avalonia.Controls.UnitTests
+{
+    public class ButtonTests
+    {
+        [Fact]
+        public void Button_Is_Disabled_When_Command_Is_Disabled()
+        {
+            var command = new TestCommand(false);
+            var target = new Button
+            {
+                Command = command,
+            };
+
+            Assert.False(target.IsEnabled);
+            command.IsEnabled = true;
+            Assert.True(target.IsEnabled);
+            command.IsEnabled = false;
+            Assert.False(target.IsEnabled);
+        }
+
+        [Fact]
+        public void Button_Is_Disabled_When_Bound_Command_Doesnt_Exist()
+        {
+            var target = new Button
+            {
+                [!Button.CommandProperty] = new Binding("Command"),
+            };
+
+            Assert.False(target.IsEnabled);
+        }
+
+        [Fact]
+        public void Button_Is_Disabled_When_Bound_Command_Is_Removed()
+        {
+            var viewModel = new
+            {
+                Command = new TestCommand(true),
+            };
+
+            var target = new Button
+            {
+                DataContext = viewModel,
+                [!Button.CommandProperty] = new Binding("Command"),
+            };
+
+            Assert.True(target.IsEnabled);
+            target.DataContext = null;
+            Assert.False(target.IsEnabled);
+        }
+
+        [Fact]
+        public void Button_Is_Enabled_When_Bound_Command_Is_Added()
+        {
+            var viewModel = new
+            {
+                Command = new TestCommand(true),
+            };
+
+            var target = new Button
+            {
+                DataContext = new object(),
+                [!Button.CommandProperty] = new Binding("Command"),
+            };
+
+            Assert.False(target.IsEnabled);
+            target.DataContext = viewModel;
+            Assert.True(target.IsEnabled);
+        }
+
+        [Fact]
+        public void Button_Is_Disabled_When_Disabled_Bound_Command_Is_Added()
+        {
+            var viewModel = new
+            {
+                Command = new TestCommand(false),
+            };
+
+            var target = new Button
+            {
+                DataContext = new object(),
+                [!Button.CommandProperty] = new Binding("Command"),
+            };
+
+            Assert.False(target.IsEnabled);
+            target.DataContext = viewModel;
+            Assert.False(target.IsEnabled);
+        }
+
+        private class TestCommand : ICommand
+        {
+            private bool _enabled;
+
+            public TestCommand(bool enabled)
+            {
+                _enabled = enabled;
+            }
+
+            public bool IsEnabled
+            {
+                get { return _enabled; }
+                set
+                {
+                    if (_enabled != value)
+                    {
+                        _enabled = value;
+                        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
+                    }
+                }
+            }
+
+            public event EventHandler CanExecuteChanged;
+
+            public bool CanExecute(object parameter) => _enabled;
+
+            public void Execute(object parameter)
+            {
+            }
+        }
+    }
+}

+ 1 - 1
tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs

@@ -388,7 +388,7 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = GetTemplate(),
                 DataContext = "Base",
-                DataTemplates = new DataTemplates
+                DataTemplates =
                 {
                     new FuncDataTemplate<Item>(x => new Button { Content = x })
                 },

+ 4 - 4
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@@ -109,10 +109,10 @@ namespace Avalonia.Controls.UnitTests
                 {
                     Template = ListBoxTemplate(),
                     DataContext = "Base",
-                    DataTemplates = new DataTemplates
-                {
-                    new FuncDataTemplate<Item>(x => new Button { Content = x })
-                },
+                    DataTemplates =
+                    {
+                        new FuncDataTemplate<Item>(x => new Button { Content = x })
+                    },
                     Items = items,
                 };
 

+ 1 - 1
tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs

@@ -88,7 +88,7 @@ namespace Avalonia.Controls.UnitTests.Presenters
             root.Child = null;
             root = new TestRoot
             {
-                DataTemplates = new DataTemplates
+                DataTemplates =
                 {
                     new FuncDataTemplate<string>(x => new Decorator()),
                 },

+ 1 - 0
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@@ -265,6 +265,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
             };
 
             var globalStyles = new Mock<IGlobalStyles>();
+            globalStyles.Setup(x => x.IsStylesInitialized).Returns(true);
             globalStyles.Setup(x => x.Styles).Returns(styles);
 
             var renderInterface = new Mock<IPlatformRenderInterface>();

+ 4 - 4
tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs

@@ -399,7 +399,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 TestTemplatedControl target;
                 var root = new TestRoot
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
@@ -435,7 +435,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
                 TestTemplatedControl target;
                 var root = new TestRoot
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
@@ -474,7 +474,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
 
                 var root = new TestRoot
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {
@@ -494,7 +494,7 @@ namespace Avalonia.Controls.UnitTests.Primitives
 
                 var root2 = new TestRoot
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.OfType<TestTemplatedControl>())
                         {

+ 2 - 2
tests/Avalonia.Controls.UnitTests/TabControlTests.cs

@@ -135,7 +135,7 @@ namespace Avalonia.Controls.UnitTests
             {
                 var root = new TestRoot
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.OfType<TabItem>())
                         {
@@ -174,7 +174,7 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = new FuncControlTemplate<TabControl>(CreateTabControlTemplate),
                 DataContext = "Base",
-                DataTemplates = new DataTemplates
+                DataTemplates =
                 {
                     new FuncDataTemplate<Item>(x => new Button { Content = x })
                 },

+ 14 - 14
tests/Avalonia.Controls.UnitTests/TreeViewTests.cs

@@ -25,9 +25,9 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 Items = CreateTestTreeData(),
-                DataTemplates = CreateNodeDataTemplate(),
             };
 
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             Assert.Equal(new[] { "Root" }, ExtractItemHeader(target, 0));
@@ -69,9 +69,9 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 Items = CreateTestTreeData(),
-                DataTemplates = CreateNodeDataTemplate(),
             };
 
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             var container = (TreeViewItem)target.ItemContainerGenerator.Containers.Single().ContainerControl;
@@ -87,7 +87,6 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 Items = tree,
-                DataTemplates = CreateNodeDataTemplate(),
             };
 
             // For TreeViewItem to find its parent TreeView, OnAttachedToLogicalTree needs
@@ -95,6 +94,7 @@ namespace Avalonia.Controls.UnitTests
             var root = new TestRoot();
             root.Child = target;
 
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             var container = target.ItemContainerGenerator.Index.ContainerFromItem(
@@ -116,11 +116,12 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 Items = tree,
-                DataTemplates = CreateNodeDataTemplate(),
             };
 
             var visualRoot = new TestRoot();
             visualRoot.Child = target;
+
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             var item = tree[0].Children[1].Children[0];
@@ -146,11 +147,12 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 Items = tree,
-                DataTemplates = CreateNodeDataTemplate(),
             };
 
             var visualRoot = new TestRoot();
             visualRoot.Child = target;
+
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             var item = tree[0].Children[1].Children[0];
@@ -191,12 +193,13 @@ namespace Avalonia.Controls.UnitTests
             var target = new TreeView
             {
                 Template = CreateTreeViewTemplate(),
-                DataTemplates = CreateNodeDataTemplate(),
                 Items = tree,
             };
 
             var root = new TestRoot();
             root.Child = target;
+
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             Assert.Equal(5, target.ItemContainerGenerator.Index.Items.Count());
@@ -221,7 +224,7 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 DataContext = "Base",
-                DataTemplates = new DataTemplates
+                DataTemplates =
                 {
                     new FuncDataTemplate<Node>(x => new Button { Content = x })
                 },
@@ -291,9 +294,9 @@ namespace Avalonia.Controls.UnitTests
             {
                 Template = CreateTreeViewTemplate(),
                 Items = data,
-                DataTemplates = CreateNodeDataTemplate(),
             };
 
+            CreateNodeDataTemplate(target);
             ApplyTemplates(target);
 
             Assert.Equal(new[] { "Root" }, ExtractItemHeader(target, 0));
@@ -328,7 +331,6 @@ namespace Avalonia.Controls.UnitTests
                 {
                     Template = CreateTreeViewTemplate(),
                     Items = data,
-                    DataTemplates = CreateNodeDataTemplate(),
                 };
 
                 var button = new Button();
@@ -341,6 +343,7 @@ namespace Avalonia.Controls.UnitTests
                     }
                 };
 
+                CreateNodeDataTemplate(target);
                 ApplyTemplates(target);
 
                 var item = data[0].Children[0];
@@ -411,12 +414,9 @@ namespace Avalonia.Controls.UnitTests
             };
         }
 
-        private DataTemplates CreateNodeDataTemplate()
+        private void CreateNodeDataTemplate(IControl control)
         {
-            return new DataTemplates
-            {
-                new TestTreeDataTemplate()
-            };
+            control.DataTemplates.Add(new TestTreeDataTemplate());
         }
 
         private IControlTemplate CreateTreeViewTemplate()

+ 1 - 1
tests/Avalonia.Controls.UnitTests/UserControlTests.cs

@@ -21,7 +21,7 @@ namespace Avalonia.Controls.UnitTests
                 var target = new UserControl();
                 var root = new TestRoot
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style(x => x.OfType<ContentControl>())
                         {

+ 5 - 1
tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj

@@ -19,4 +19,8 @@
     <ProjectReference Include="..\..\src\Avalonia.Styling\Avalonia.Styling.csproj" />
     <ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />
   </ItemGroup>
-</Project>
+</Project>
+  <ItemGroup>
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+</Project>

+ 1 - 0
tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs

@@ -193,6 +193,7 @@ namespace Avalonia.Layout.UnitTests
                 .Bind<IWindowingPlatform>().ToConstant(new Avalonia.Controls.UnitTests.WindowingPlatformMock(() => windowImpl.Object));
 
             var theme = new DefaultTheme();
+            globalStyles.Setup(x => x.IsStylesInitialized).Returns(true);
             globalStyles.Setup(x => x.Styles).Returns(theme);
         }
     }

+ 1 - 1
tests/Avalonia.LeakTests/ControlTests.cs

@@ -276,7 +276,7 @@ namespace Avalonia.LeakTests
                     {
                         Content = target = new TreeView
                         {
-                            DataTemplates = new DataTemplates
+                            DataTemplates =
                             {
                                 new FuncTreeDataTemplate<Node>(
                                     x => new TextBlock { Text = x.Name },

+ 39 - 16
tests/Avalonia.Markup.UnitTests/Data/ExpressionObserverTests_Property.cs

@@ -67,49 +67,69 @@ namespace Avalonia.Markup.UnitTests.Data
         }
 
         [Fact]
-        public async Task Should_Return_UnsetValue_For_Root_Null()
+        public async Task Should_Return_BindingNotification_Error_For_Root_Null()
         {
             var data = new Class3 { Foo = "foo" };
             var target = new ExpressionObserver(default(object), "Foo");
             var result = await target.Take(1);
 
-            Assert.Equal(AvaloniaProperty.UnsetValue, result);
+            Assert.Equal(
+                new BindingNotification(
+                        new MarkupBindingChainException("Null value", "Foo", string.Empty),
+                        BindingErrorType.Error,
+                        AvaloniaProperty.UnsetValue),
+                result);
 
             GC.KeepAlive(data);
         }
 
         [Fact]
-        public async Task Should_Return_UnsetValue_For_Root_UnsetValue()
+        public async Task Should_Return_BindingNotification_Error_For_Root_UnsetValue()
         {
             var data = new Class3 { Foo = "foo" };
             var target = new ExpressionObserver(AvaloniaProperty.UnsetValue, "Foo");
             var result = await target.Take(1);
 
-            Assert.Equal(AvaloniaProperty.UnsetValue, result);
+            Assert.Equal(
+                new BindingNotification(
+                        new MarkupBindingChainException("Null value", "Foo", string.Empty),
+                        BindingErrorType.Error,
+                        AvaloniaProperty.UnsetValue),
+                result);
 
             GC.KeepAlive(data);
         }
 
         [Fact]
-        public async Task Should_Return_UnsetValue_For_Observable_Root_Null()
+        public async Task Should_Return_BindingNotification_Error_For_Observable_Root_Null()
         {
             var data = new Class3 { Foo = "foo" };
             var target = new ExpressionObserver(Observable.Return(default(object)), "Foo");
             var result = await target.Take(1);
 
-            Assert.Equal(AvaloniaProperty.UnsetValue, result);
+            Assert.Equal(
+                new BindingNotification(
+                        new MarkupBindingChainException("Null value", "Foo", string.Empty),
+                        BindingErrorType.Error,
+                        AvaloniaProperty.UnsetValue),
+                result);
 
             GC.KeepAlive(data);
         }
 
         [Fact]
-        public async Task Should_Return_UnsetValue_For_Observable_Root_UnsetValue()
+        public async void Should_Return_BindingNotification_Error_For_Observable_Root_UnsetValue()
         {
             var data = new Class3 { Foo = "foo" };
             var target = new ExpressionObserver(Observable.Return(AvaloniaProperty.UnsetValue), "Foo");
             var result = await target.Take(1);
 
-            Assert.Equal(AvaloniaProperty.UnsetValue, result);
+            Assert.Equal(
+                new BindingNotification(
+                        new MarkupBindingChainException("Null value", "Foo", string.Empty),
+                        BindingErrorType.Error,
+                        AvaloniaProperty.UnsetValue),
+                result);
 
             GC.KeepAlive(data);
         }
@@ -117,7 +137,7 @@ namespace Avalonia.Markup.UnitTests.Data
         [Fact]
         public async Task Should_Get_Simple_Property_Chain()
         {
-            var data = new { Foo = new { Bar = new { Baz = "baz" } }  };
+            var data = new { Foo = new { Bar = new { Baz = "baz" } } };
             var target = new ExpressionObserver(data, "Foo.Bar.Baz");
             var result = await target.Take(1);
 
@@ -215,7 +235,7 @@ namespace Avalonia.Markup.UnitTests.Data
             var target = new ExpressionObserver(data, "Bar");
             var result = new List<object>();
 
-            var sub = target.Subscribe(x => result.Add(x));            
+            var sub = target.Subscribe(x => result.Add(x));
 
             Assert.Equal(new[] { "foo" }, result);
 
@@ -305,7 +325,7 @@ namespace Avalonia.Markup.UnitTests.Data
             data.Next = old;
 
             Assert.Equal(
-                new object[] 
+                new object[]
                 {
                     "bar",
                     new BindingNotification(
@@ -313,7 +333,7 @@ namespace Avalonia.Markup.UnitTests.Data
                         BindingErrorType.Error,
                         AvaloniaProperty.UnsetValue),
                     "bar"
-                }, 
+                },
                 result);
 
             sub.Dispose();
@@ -473,7 +493,7 @@ namespace Avalonia.Markup.UnitTests.Data
         [Fact]
         public void SetValue_Should_Return_False_For_Missing_Property()
         {
-            var data = new Class1 { Next = new WithoutBar()};
+            var data = new Class1 { Next = new WithoutBar() };
             var target = new ExpressionObserver(data, "Next.Bar");
 
             using (target.Subscribe(_ => { }))
@@ -545,12 +565,15 @@ namespace Avalonia.Markup.UnitTests.Data
             update.OnNext(Unit.Default);
 
             Assert.Equal(
-                new object[] 
+                new object[]
                 {
                     "foo",
                     "bar",
-                    AvaloniaProperty.UnsetValue,
-                }, 
+                    new BindingNotification(
+                        new MarkupBindingChainException("Null value", "Foo", string.Empty),
+                        BindingErrorType.Error,
+                        AvaloniaProperty.UnsetValue)
+                },
                 result);
 
             Assert.Equal(0, first.PropertyChangedSubscriptionCount);

+ 2 - 2
tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs

@@ -302,12 +302,12 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
 
             // Bind Foo and Bar to the VM.
             target.Bind(OldDataContextTest.FooProperty, fooBinding);
-            //target.Bind(OldDataContextTest.BarProperty, barBinding);
+            target.Bind(OldDataContextTest.BarProperty, barBinding);
             target.DataContext = vm;
 
             // Make sure the control's Foo and Bar properties are read from the VM
             Assert.Equal(1, target.GetValue(OldDataContextTest.FooProperty));
-            //Assert.Equal(2, target.GetValue(OldDataContextTest.BarProperty));
+            Assert.Equal(2, target.GetValue(OldDataContextTest.BarProperty));
 
             // Set DataContext to null.
             target.DataContext = null;

+ 1 - 1
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlBindingTests.cs

@@ -37,7 +37,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
 
             LogCallback checkLogMessage = (level, area, src, mt, pv) =>
             {
-                if (level == LogEventLevel.Error &&
+                if (level == LogEventLevel.Warning &&
                     area == LogArea.Binding &&
                     mt == "Error in binding to {Target}.{Property}: {Message}" &&
                     pv.Length == 3 &&

+ 10 - 10
tests/Avalonia.Styling.UnitTests/ResourceTests.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Styling.UnitTests
 
             var tree = new Decorator
             {
-                Styles = new Styles
+                Styles =
                 {
                     new Style
                     {
@@ -29,7 +29,7 @@ namespace Avalonia.Styling.UnitTests
                 },
                 Child = target = new Border
                 {
-                    Styles = new Styles
+                    Styles =
                     {
                         new Style
                         {
@@ -60,16 +60,16 @@ namespace Avalonia.Styling.UnitTests
 
             var tree = target = new Border
             {
-                Styles = new Styles
+                Styles =
+                {
+                    new Style
                     {
-                        new Style
+                        Resources = new StyleResources
                         {
-                            Resources = new StyleResources
-                            {
-                                { "Foo", "foo" },
-                            }
-                        },
-                    }
+                            { "Foo", "foo" },
+                        }
+                    },
+                }
             };
 
             Assert.Equal(AvaloniaProperty.UnsetValue, target.FindStyleResource("Baz"));

+ 4 - 0
tests/Avalonia.Visuals.UnitTests/Media/PathMarkupParserTests.cs

@@ -74,6 +74,10 @@ namespace Avalonia.Visuals.UnitTests.Media
             " 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 ")]
+        [InlineData(
+            "F1M16,12C16,14.209 14.209,16 12,16 9.791,16 8,14.209 8,12 8,11.817 8.03,11.644 8.054,11.467L6.585,10 4,10 " + 
+            "4,6.414 2.5,7.914 0,5.414 0,3.586 3.586,0 4.414,0 7.414,3 7.586,3 9,1.586 11.914,4.5 10.414,6 " + 
+            "12.461,8.046C14.45,8.278,16,9.949,16,12")]
         public void Should_Parse(string pathData)
         {
             using (AvaloniaLocator.EnterScope())