Browse Source

Merge branch 'master' into netstandard2.0-migration

Nikita Tsukanov 8 years ago
parent
commit
abd23cce8d
38 changed files with 505 additions and 261 deletions
  1. 1 1
      build/Moq.props
  2. 0 19
      build/UnitTests.NetCore.targets
  3. 36 17
      samples/ControlCatalog/Pages/ToolTipPage.xaml
  4. 9 6
      src/Avalonia.Controls/Application.cs
  5. 10 12
      src/Avalonia.Controls/Control.cs
  6. 8 6
      src/Avalonia.Controls/IControl.cs
  7. 1 5
      src/Avalonia.Controls/IGlobalDataTemplates.cs
  8. 16 10
      src/Avalonia.Controls/Primitives/Popup.cs
  9. 15 9
      src/Avalonia.Controls/Templates/DataTemplateExtensions.cs
  10. 27 0
      src/Avalonia.Controls/Templates/IDataTemplateHost.cs
  11. 156 80
      src/Avalonia.Controls/ToolTip.cs
  12. 98 0
      src/Avalonia.Controls/ToolTipService.cs
  13. 1 1
      src/Avalonia.Diagnostics/DevTools.xaml.cs
  14. 1 1
      src/Avalonia.Diagnostics/Views/ControlDetailsView.cs
  15. 11 2
      src/Avalonia.DotNetFrameworkRuntime/AppBuilder.cs
  16. 1 0
      src/Avalonia.HtmlRenderer/Avalonia.HtmlRenderer.csproj
  17. 12 8
      src/Avalonia.Interactivity/Interactive.cs
  18. 11 1
      src/Avalonia.Styling/Styling/IStyleHost.cs
  19. 7 4
      src/Avalonia.Styling/Styling/StyleExtensions.cs
  20. 4 1
      src/Avalonia.Styling/Styling/Styler.cs
  21. 1 0
      src/Linux/Avalonia.LinuxFramebuffer/NativeUnsafeMethods.cs
  22. 0 1
      src/Windows/Avalonia.Designer/AppHost/HostedAppModel.cs
  23. 33 5
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  24. 1 1
      src/Windows/Avalonia.Win32/Win32Platform.cs
  25. 3 3
      src/Windows/Avalonia.Win32/WindowImpl.cs
  26. 1 1
      tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
  27. 4 4
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
  28. 1 1
      tests/Avalonia.Controls.UnitTests/Presenters/ContentPresenterTests_Unrooted.cs
  29. 1 0
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  30. 4 4
      tests/Avalonia.Controls.UnitTests/Primitives/TemplatedControlTests.cs
  31. 2 2
      tests/Avalonia.Controls.UnitTests/TabControlTests.cs
  32. 14 14
      tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
  33. 1 1
      tests/Avalonia.Controls.UnitTests/UserControlTests.cs
  34. 1 30
      tests/Avalonia.Input.UnitTests/Avalonia.Input.UnitTests.csproj
  35. 1 0
      tests/Avalonia.Layout.UnitTests/FullLayoutTests.cs
  36. 1 1
      tests/Avalonia.LeakTests/ControlTests.cs
  37. 1 0
      tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj
  38. 10 10
      tests/Avalonia.Styling.UnitTests/ResourceTests.cs

+ 1 - 1
build/Moq.props

@@ -1,5 +1,5 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="Moq" Version="4.7.25" />
+    <PackageReference Include="Moq" Version="4.7.99" />
   </ItemGroup>
 </Project>

+ 0 - 19
build/UnitTests.NetCore.targets

@@ -3,25 +3,6 @@
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
-  </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="System.Threading.Thread" Version="4.3.0" />
   </ItemGroup>

+ 36 - 17
samples/ControlCatalog/Pages/ToolTipPage.xaml

@@ -1,22 +1,41 @@
 <UserControl xmlns="https://github.com/avaloniaui">
-  <StackPanel Orientation="Vertical" Gap="4">
-    <TextBlock Classes="h1">ToolTip</TextBlock>
-    <TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
+    <StackPanel Orientation="Vertical"
+                Gap="4">
+        <TextBlock Classes="h1">ToolTip</TextBlock>
+        <TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
 
-    <StackPanel Orientation="Horizontal"
+        <Grid RowDefinitions="Auto,Auto"
+              ColumnDefinitions="Auto,Auto"
               Margin="0,16,0,0"
-              HorizontalAlignment="Center"
-              Gap="16">
-      <Border Background="{StyleResource ThemeAccentBrush}"
-              Padding="48,48,48,48">
-        <ToolTip.Tip>
-          <StackPanel>
-            <TextBlock Classes="h1">ToolTip</TextBlock>
-            <TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
-          </StackPanel>
-        </ToolTip.Tip>
-        <TextBlock>Hover Here</TextBlock>
-      </Border>
+              HorizontalAlignment="Center">
+            <Border Grid.Column="0"
+                    Grid.Row="1"
+                    Background="{StyleResource ThemeAccentBrush}"
+                    Margin="5"
+                    Padding="50"
+                    ToolTip.Tip="This is a ToolTip">
+                <TextBlock>Hover Here</TextBlock>
+            </Border>
+            <CheckBox Grid.Column="1"
+                      Margin="5"
+                      Grid.Row="0"
+                      IsChecked="{Binding ElementName=Border, Path=(ToolTip.IsOpen)}"
+                      Content="ToolTip Open" />
+            <Border Name="Border"
+                    Grid.Column="1"
+                    Grid.Row="1"
+                    Background="{StyleResource ThemeAccentBrush}"
+                    Margin="5"
+                    Padding="50"
+                    ToolTip.Placement="Bottom">
+                <ToolTip.Tip>
+                    <StackPanel>
+                        <TextBlock Classes="h1">ToolTip</TextBlock>
+                        <TextBlock Classes="h2">A control which pops up a hint when a control is hovered</TextBlock>
+                    </StackPanel>
+                </ToolTip.Tip>
+                <TextBlock>ToolTip bottom placement</TextBlock>
+            </Border>
+        </Grid>
     </StackPanel>
-  </StackPanel>
 </UserControl>

+ 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>

+ 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; }
     }
 }

+ 16 - 10
src/Avalonia.Controls/Primitives/Popup.cs

@@ -277,7 +277,7 @@ namespace Avalonia.Controls.Primitives
         {
             base.OnDetachedFromLogicalTree(e);
             _topLevel = null;
-            
+
             if (_popupRoot != null)
             {
                 ((ISetLogicalParent)_popupRoot).SetParent(null);
@@ -327,34 +327,40 @@ namespace Avalonia.Controls.Primitives
         /// </summary>
         /// <returns>The popup's position in screen coordinates.</returns>
         protected virtual Point GetPosition()
+        {
+            return GetPosition(PlacementTarget ?? this.GetVisualParent<Control>(), PlacementMode, PopupRoot, 
+                HorizontalOffset, VerticalOffset);
+        }
+
+        internal static Point GetPosition(Control target, PlacementMode placement, PopupRoot popupRoot, double horizontalOffset, double verticalOffset)
         {
             var zero = default(Point);
-            var mode = PlacementMode;
-            var target = PlacementTarget ?? this.GetVisualParent<Control>();
+            var mode = placement;
 
             if (target?.GetVisualRoot() == null)
             {
                 mode = PlacementMode.Pointer;
-            }            
+            }
 
             switch (mode)
             {
                 case PlacementMode.Pointer:
-                    if(PopupRoot != 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 (((IInputRoot)PopupRoot)?.MouseDevice?.Position ?? default(Point)) + screenOffset;
+                        var screenOffset = new Point(horizontalOffset * (popupRoot as ILayoutRoot).LayoutScaling,
+                            verticalOffset * (popupRoot as ILayoutRoot).LayoutScaling);
+                        return (((IInputRoot)popupRoot)?.MouseDevice?.Position ?? default(Point)) + screenOffset;
                     }
 
                     return default(Point);
 
                 case PlacementMode.Bottom:
-
-                    return target?.PointToScreen(new Point(0 + HorizontalOffset, target.Bounds.Height + VerticalOffset)) ?? zero;
+                    return target?.PointToScreen(new Point(0 + horizontalOffset, target.Bounds.Height + verticalOffset)) ??
+                           zero;
 
                 case PlacementMode.Right:
-                    return target?.PointToScreen(new Point(target.Bounds.Width + HorizontalOffset, 0 + VerticalOffset)) ?? zero;
+                    return target?.PointToScreen(new Point(target.Bounds.Width + horizontalOffset, 0 + verticalOffset)) ?? zero;
 
                 default:
                     throw new InvalidOperationException("Invalid value for Popup.PlacementMode");

+ 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; }
+    }
+}

+ 156 - 80
src/Avalonia.Controls/ToolTip.cs

@@ -3,11 +3,7 @@
 
 using System;
 using System.Reactive.Linq;
-using System.Reactive.Subjects;
 using Avalonia.Controls.Primitives;
-using Avalonia.Input;
-using Avalonia.Threading;
-using Avalonia.VisualTree;
 
 namespace Avalonia.Controls
 {
@@ -29,29 +25,50 @@ namespace Avalonia.Controls
             AvaloniaProperty.RegisterAttached<ToolTip, Control, object>("Tip");
 
         /// <summary>
-        /// The popup window used to display the active tooltip.
+        /// Defines the ToolTip.IsOpen attached property.
         /// </summary>
-        private static PopupRoot s_popup;
+        public static readonly AttachedProperty<bool> IsOpenProperty =
+            AvaloniaProperty.RegisterAttached<ToolTip, Control, bool>("IsOpen");
 
         /// <summary>
-        /// The control that the currently visible tooltip is attached to.
+        /// Defines the ToolTip.Placement property.
         /// </summary>
-        private static Control s_current;
+        public static readonly AttachedProperty<PlacementMode> PlacementProperty =
+            AvaloniaProperty.RegisterAttached<Popup, Control, PlacementMode>("Placement", defaultValue: PlacementMode.Pointer);
 
         /// <summary>
-        /// Observable fired when a tooltip should be displayed for a control. The output from this
-        /// observable is throttled and calls <see cref="ShowToolTip(Control)"/> when the time
-        /// period expires.
+        /// Defines the ToolTip.HorizontalOffset property.
         /// </summary>
-        private static readonly Subject<Control> s_show = new Subject<Control>();
+        public static readonly AttachedProperty<double> HorizontalOffsetProperty =
+            AvaloniaProperty.RegisterAttached<Popup, Control, double>("HorizontalOffset");
+
+        /// <summary>
+        /// Defines the ToolTip.VerticalOffset property.
+        /// </summary>
+        public static readonly AttachedProperty<double> VerticalOffsetProperty =
+            AvaloniaProperty.RegisterAttached<Popup, Control, double>("VerticalOffset", 20);
+
+        /// <summary>
+        /// Defines the ToolTip.ShowDelay property.
+        /// </summary>
+        public static readonly AttachedProperty<int> ShowDelayProperty =
+            AvaloniaProperty.RegisterAttached<Popup, Control, int>("ShowDelay", 400);
+
+        /// <summary>
+        /// Stores the curernt <see cref="ToolTip"/> instance in the control.
+        /// </summary>
+        private static readonly AttachedProperty<ToolTip> ToolTipProperty =
+            AvaloniaProperty.RegisterAttached<ToolTip, Control, ToolTip>("ToolTip");
+
+        private PopupRoot _popup;
 
         /// <summary>
         /// Initializes static members of the <see cref="ToolTip"/> class.
         /// </summary>
         static ToolTip()
         {
-            TipProperty.Changed.Subscribe(TipChanged);
-            s_show.Throttle(TimeSpan.FromSeconds(0.5), AvaloniaScheduler.Instance).Subscribe(ShowToolTip);
+            TipProperty.Changed.Subscribe(ToolTipService.Instance.TipChanged);
+            IsOpenProperty.Changed.Subscribe(IsOpenChanged);
         }
 
         /// <summary>
@@ -77,101 +94,160 @@ namespace Avalonia.Controls
         }
 
         /// <summary>
-        /// called when the <see cref="TipProperty"/> property changes on a control.
+        /// Gets the value of the ToolTip.IsOpen attached property.
         /// </summary>
-        /// <param name="e">The event args.</param>
-        private static void TipChanged(AvaloniaPropertyChangedEventArgs e)
+        /// <param name="element">The control to get the property from.</param>
+        /// <returns>
+        /// A value indicating whether the tool tip is visible.
+        /// </returns>
+        public static bool GetIsOpen(Control element)
         {
-            var control = (Control)e.Sender;
+            return element.GetValue(IsOpenProperty);
+        }
 
-            if (e.OldValue != null)
-            {
-                control.PointerEnter -= ControlPointerEnter;
-                control.PointerLeave -= ControlPointerLeave;
-            }
+        /// <summary>
+        /// Sets the value of the ToolTip.IsOpen attached property.
+        /// </summary>
+        /// <param name="element">The control to get the property from.</param>
+        /// <param name="value">A value indicating whether the tool tip is visible.</param>
+        public static void SetIsOpen(Control element, bool value)
+        {
+            element.SetValue(IsOpenProperty, value);
+        }
 
-            if (e.NewValue != null)
-            {
-                control.PointerEnter += ControlPointerEnter;
-                control.PointerLeave += ControlPointerLeave;
-            }
+        /// <summary>
+        /// Gets the value of the ToolTip.Placement attached property.
+        /// </summary>
+        /// <param name="element">The control to get the property from.</param>
+        /// <returns>
+        /// A value indicating how the tool tip is positioned.
+        /// </returns>
+        public static PlacementMode GetPlacement(Control element)
+        {
+            return element.GetValue(PlacementProperty);
         }
 
         /// <summary>
-        /// Shows a tooltip for the specified control.
+        /// Sets the value of the ToolTip.Placement attached property.
         /// </summary>
-        /// <param name="control">The control.</param>
-        private static void ShowToolTip(Control control)
+        /// <param name="element">The control to get the property from.</param>
+        /// <param name="value">A value indicating how the tool tip is positioned.</param>
+        public static void SetPlacement(Control element, PlacementMode value)
         {
-            if (control != null && control.IsVisible && control.GetVisualRoot() != null)
-            {
-                var cp = (control.GetVisualRoot() as IInputRoot)?.MouseDevice?.GetPosition(control);
+            element.SetValue(PlacementProperty, value);
+        }
 
-                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);
-                    }
-
-                ((ISetLogicalParent)s_popup).SetParent(control);
-                    ((ToolTip)s_popup.Content).Content = GetTip(control);
-                    s_popup.Position = position;
-                    s_popup.Show();
-
-                    s_current = control;
-                }
-            }
+        /// <summary>
+        /// Gets the value of the ToolTip.HorizontalOffset attached property.
+        /// </summary>
+        /// <param name="element">The control to get the property from.</param>
+        /// <returns>
+        /// A value indicating how the tool tip is positioned.
+        /// </returns>
+        public static double GetHorizontalOffset(Control element)
+        {
+            return element.GetValue(HorizontalOffsetProperty);
+        }
+
+        /// <summary>
+        /// Sets the value of the ToolTip.HorizontalOffset attached property.
+        /// </summary>
+        /// <param name="element">The control to get the property from.</param>
+        /// <param name="value">A value indicating how the tool tip is positioned.</param>
+        public static void SetHorizontalOffset(Control element, double value)
+        {
+            element.SetValue(HorizontalOffsetProperty, value);
+        }
+
+        /// <summary>
+        /// Gets the value of the ToolTip.VerticalOffset attached property.
+        /// </summary>
+        /// <param name="element">The control to get the property from.</param>
+        /// <returns>
+        /// A value indicating how the tool tip is positioned.
+        /// </returns>
+        public static double GetVerticalOffset(Control element)
+        {
+            return element.GetValue(VerticalOffsetProperty);
+        }
+
+        /// <summary>
+        /// Sets the value of the ToolTip.VerticalOffset attached property.
+        /// </summary>
+        /// <param name="element">The control to get the property from.</param>
+        /// <param name="value">A value indicating how the tool tip is positioned.</param>
+        public static void SetVerticalOffset(Control element, double value)
+        {
+            element.SetValue(VerticalOffsetProperty, value);
         }
 
         /// <summary>
-        /// Called when the pointer enters a control with an attached tooltip.
+        /// Gets the value of the ToolTip.ShowDelay attached property.
         /// </summary>
-        /// <param name="sender">The event sender.</param>
-        /// <param name="e">The event args.</param>
-        private static void ControlPointerEnter(object sender, PointerEventArgs e)
+        /// <param name="element">The control to get the property from.</param>
+        /// <returns>
+        /// A value indicating the time, in milliseconds, before a tool tip opens.
+        /// </returns>
+        public static int GetShowDelay(Control element)
         {
-            s_current = (Control)sender;
-            s_show.OnNext(s_current);
+            return element.GetValue(ShowDelayProperty);
         }
 
         /// <summary>
-        /// Called when the pointer leaves a control with an attached tooltip.
+        /// Sets the value of the ToolTip.ShowDelay attached property.
         /// </summary>
-        /// <param name="sender">The event sender.</param>
-        /// <param name="e">The event args.</param>
-        private static void ControlPointerLeave(object sender, PointerEventArgs e)
+        /// <param name="element">The control to get the property from.</param>
+        /// <param name="value">A value indicating the time, in milliseconds, before a tool tip opens.</param>
+        public static void SetShowDelay(Control element, int value)
         {
-            var control = (Control)sender;
+            element.SetValue(ShowDelayProperty, value);
+        }
+
+        private static void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            var control = (Control)e.Sender;
 
-            if (control == s_current)
+            if ((bool)e.NewValue)
             {
-                if (s_popup != null)
+                var tip = GetTip(control);
+                if (tip == null) return;
+
+                var toolTip = control.GetValue(ToolTipProperty);
+                if (toolTip == null || (tip != toolTip && tip != toolTip.Content))
                 {
-                    DisposeTooltip();
-                    s_show.OnNext(null);
+                    toolTip?.Close();
+
+                    toolTip = tip as ToolTip ?? new ToolTip { Content = tip };
+                    control.SetValue(ToolTipProperty, toolTip);
                 }
+
+                toolTip.Open(control);
+            }
+            else
+            {
+                var toolTip = control.GetValue(ToolTipProperty);
+                toolTip?.Close();
             }
         }
 
-        private static void DisposeTooltip()
+        private void Open(Control control)
         {
-            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;
+            Close();
+
+            _popup = new PopupRoot { Content = this };
+            ((ISetLogicalParent)_popup).SetParent(control);
+            _popup.Position = Popup.GetPosition(control, GetPlacement(control), _popup,
+                GetHorizontalOffset(control), GetVerticalOffset(control));
+            _popup.Show();
+        }
 
-                // Dispose of the popup.
-                s_popup.Dispose();
-                s_popup = null;
+        private void Close()
+        {
+            if (_popup != null)
+            {
+                _popup.Content = null;
+                _popup.Hide();
+                _popup = null;
             }
         }
     }

+ 98 - 0
src/Avalonia.Controls/ToolTipService.cs

@@ -0,0 +1,98 @@
+using System;
+using Avalonia.Input;
+using Avalonia.Threading;
+
+namespace Avalonia.Controls
+{
+    /// <summary>
+    /// Handeles <see cref="ToolTip"/> interaction with controls.
+    /// </summary>
+    internal sealed class ToolTipService
+    {
+        public static ToolTipService Instance { get; } = new ToolTipService();
+
+        private DispatcherTimer _timer;
+
+        private ToolTipService() { }
+
+        /// <summary>
+        /// called when the <see cref="ToolTip.TipProperty"/> property changes on a control.
+        /// </summary>
+        /// <param name="e">The event args.</param>
+        internal void TipChanged(AvaloniaPropertyChangedEventArgs e)
+        {
+            var control = (Control)e.Sender;
+
+            if (e.OldValue != null)
+            {
+                control.PointerEnter -= ControlPointerEnter;
+                control.PointerLeave -= ControlPointerLeave;
+            }
+
+            if (e.NewValue != null)
+            {
+                control.PointerEnter += ControlPointerEnter;
+                control.PointerLeave += ControlPointerLeave;
+            }
+        }
+
+        /// <summary>
+        /// Called when the pointer enters a control with an attached tooltip.
+        /// </summary>
+        /// <param name="sender">The event sender.</param>
+        /// <param name="e">The event args.</param>
+        private void ControlPointerEnter(object sender, PointerEventArgs e)
+        {
+            StopTimer();
+
+            var control = (Control)sender;
+            var showDelay = ToolTip.GetShowDelay(control);
+            if (showDelay == 0)
+            {
+                Open(control);
+            }
+            else
+            {
+                StartShowTimer(showDelay, control);
+            }
+        }
+
+        /// <summary>
+        /// Called when the pointer leaves a control with an attached tooltip.
+        /// </summary>
+        /// <param name="sender">The event sender.</param>
+        /// <param name="e">The event args.</param>
+        private void ControlPointerLeave(object sender, PointerEventArgs e)
+        {
+            var control = (Control)sender;
+            Close(control);
+        }
+
+        private void StartShowTimer(int showDelay, Control control)
+        {
+            _timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(showDelay) };
+            _timer.Tick += (o, e) => Open(control);
+            _timer.Start();
+        }
+
+        private void Open(Control control)
+        {
+            StopTimer();
+
+            ToolTip.SetIsOpen(control, true);
+        }
+
+        private void Close(Control control)
+        {
+            StopTimer();
+
+            ToolTip.SetIsOpen(control, false);
+        }
+
+        private void StopTimer()
+        {
+            _timer?.Stop();
+            _timer = null;
+        }
+    }
+}

+ 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>())
                         {

+ 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),

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

@@ -4,6 +4,7 @@
     <EnableDefaultCompileItems>False</EnableDefaultCompileItems>
     <EnableDefaultItems>False</EnableDefaultItems>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+    <NoWarn>CS0436</NoWarn>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
     <DebugSymbols>true</DebugSymbols>

+ 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())
                 {

+ 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);
+            }
         }
     }
 }

+ 1 - 0
src/Linux/Avalonia.LinuxFramebuffer/NativeUnsafeMethods.cs

@@ -72,6 +72,7 @@ namespace Avalonia.LinuxFramebuffer
         FB_VBLANK_HAVE_VSYNC = 0x100 /* verical syncs can be detected */
     }
 
+    [StructLayout(LayoutKind.Sequential)]
     unsafe struct fb_vblank {
         public VBlankFlags flags;			/* FB_VBLANK flags */
         __u32 count;			/* counter of retraces since boot */

+ 0 - 1
src/Windows/Avalonia.Designer/AppHost/HostedAppModel.cs

@@ -86,7 +86,6 @@ namespace Avalonia.Designer.AppHost
         }
 
         double _currentScalingFactor = 1;
-        private string _color;
         private string _background;
 
         public event PropertyChangedEventHandler PropertyChanged;

+ 33 - 5
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@@ -699,10 +699,40 @@ namespace Avalonia.Win32.Interop
         public static extern int GetSystemMetrics(SystemMetric smIndex);
 
         [DllImport("user32.dll", SetLastError = true)]
-        public static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
+        public static extern uint GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+        [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLong")]
+        public static extern uint GetWindowLong32b(IntPtr hWnd, int nIndex);
+
+        public static uint GetWindowLong(IntPtr hWnd, int nIndex)
+        {
+            if(IntPtr.Size == 4)
+            {
+                return GetWindowLong32b(hWnd, nIndex);
+            }
+            else
+            {
+                return GetWindowLongPtr(hWnd, nIndex);
+            }
+        }
+
+        [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
+        private static extern uint SetWindowLong32b(IntPtr hWnd, int nIndex, uint value);
 
         [DllImport("user32.dll", SetLastError = true)]
-        public static extern uint SetWindowLong(IntPtr hWnd, int nIndex, uint value);
+        private static extern uint SetWindowLongPtr(IntPtr hWnd, int nIndex, uint value);
+
+        public static uint SetWindowLong(IntPtr hWnd, int nIndex, uint value)
+        {
+            if (IntPtr.Size == 4)
+            {
+                return SetWindowLong32b(hWnd, nIndex, value);
+            }
+            else
+            {
+                return SetWindowLongPtr(hWnd, nIndex, value);
+            }
+        }
 
         [DllImport("user32.dll", SetLastError = true)]
         public static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
@@ -922,9 +952,7 @@ namespace Avalonia.Win32.Interop
         [StructLayout(LayoutKind.Sequential)]
         internal class MONITORINFO
         {
-#pragma warning disable CS0618 // Type or member is obsolete
-            public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));
-#pragma warning restore CS0618 // Type or member is obsolete
+            public int cbSize = Marshal.SizeOf<MONITORINFO>();
             public RECT rcMonitor = new RECT();
             public RECT rcWork = new RECT();
             public int dwFlags = 0;

+ 1 - 1
src/Windows/Avalonia.Win32/Win32Platform.cs

@@ -167,7 +167,7 @@ namespace Avalonia.Win32
 
             UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX
             {
-                cbSize = Marshal.SizeOf(typeof(UnmanagedMethods.WNDCLASSEX)),
+                cbSize = Marshal.SizeOf<UnmanagedMethods.WNDCLASSEX>(),
                 lpfnWndProc = _wndProcDelegate,
                 hInstance = UnmanagedMethods.GetModuleHandle(null),
                 lpszClassName = "AvaloniaMessageWindow " + Guid.NewGuid(),

+ 3 - 3
src/Windows/Avalonia.Win32/WindowImpl.cs

@@ -426,7 +426,7 @@ namespace Avalonia.Win32
 
                 case UnmanagedMethods.WindowsMessage.WM_DPICHANGED:
                     var dpi = ToInt32(wParam) & 0xffff;
-                    var newDisplayRect = (UnmanagedMethods.RECT)Marshal.PtrToStructure(lParam, typeof(UnmanagedMethods.RECT));
+                    var newDisplayRect = Marshal.PtrToStructure<UnmanagedMethods.RECT>(lParam);
                     Position = new Point(newDisplayRect.left, newDisplayRect.top);
                     _scaling = dpi / 96.0;
                     ScalingChanged?.Invoke(_scaling);
@@ -494,7 +494,7 @@ namespace Avalonia.Win32
                     {
                         var tm = new UnmanagedMethods.TRACKMOUSEEVENT
                         {
-                            cbSize = Marshal.SizeOf(typeof(UnmanagedMethods.TRACKMOUSEEVENT)),
+                            cbSize = Marshal.SizeOf<UnmanagedMethods.TRACKMOUSEEVENT>(),
                             dwFlags = 2,
                             hwndTrack = _hwnd,
                             dwHoverTime = 0,
@@ -619,7 +619,7 @@ namespace Avalonia.Win32
 
             UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX
             {
-                cbSize = Marshal.SizeOf(typeof(UnmanagedMethods.WNDCLASSEX)),
+                cbSize = Marshal.SizeOf<UnmanagedMethods.WNDCLASSEX>(),
                 style = 0,
                 lpfnWndProc = _wndProcDelegate,
                 hInstance = UnmanagedMethods.GetModuleHandle(null),

+ 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>())
                         {

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

@@ -3,35 +3,6 @@
     <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
     <OutputType>Library</OutputType>
   </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-    <DocumentationFile>bin\Debug\Avalonia.Input.UnitTests.XML</DocumentationFile>
-    <NoWarn>CS1591</NoWarn>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Xml" />
-    <Reference Include="WindowsBase" />
-  </ItemGroup>
   <Import Project="..\..\build\UnitTests.NetCore.targets" />
   <Import Project="..\..\build\Moq.props" />
   <Import Project="..\..\build\XUnit.props" />
@@ -49,6 +20,6 @@
     <ProjectReference Include="..\Avalonia.UnitTests\Avalonia.UnitTests.csproj" />
   </ItemGroup>
   <ItemGroup>
-    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+    <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 },

+ 1 - 0
tests/Avalonia.Styling.UnitTests/Avalonia.Styling.UnitTests.csproj

@@ -2,6 +2,7 @@
   <PropertyGroup>
     <TargetFrameworks>net461;netcoreapp2.0</TargetFrameworks>
     <OutputType>Library</OutputType>
+    <NoWarn>CS0067</NoWarn>
   </PropertyGroup>
   <Import Project="..\..\build\UnitTests.NetCore.targets" />
   <Import Project="..\..\build\Moq.props" />

+ 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"));