diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs index ef253a28e2..516da813ef 100644 --- a/src/Avalonia.Controls/Control.cs +++ b/src/Avalonia.Controls/Control.cs @@ -17,7 +17,9 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Logging; using Avalonia.LogicalTree; +using Avalonia.Rendering; using Avalonia.Styling; +using Avalonia.VisualTree; namespace Avalonia.Controls { @@ -33,7 +35,7 @@ namespace Avalonia.Controls /// - Implements to allow styling to work on the control. /// - Implements to form part of a logical tree. /// - public class Control : InputElement, IControl, INamed, ISetInheritanceParent, ISetLogicalParent, ISupportInitialize + public class Control : InputElement, IControl, INamed, ISetInheritanceParent, ISetLogicalParent, ISupportInitialize, IVisualBrushInitialize { /// /// Defines the property. @@ -460,6 +462,38 @@ namespace Avalonia.Controls InheritanceParent = parent; } + /// + void IVisualBrushInitialize.EnsureInitialized() + { + if (VisualRoot == null) + { + if (!IsInitialized) + { + foreach (var i in this.GetSelfAndVisualDescendents()) + { + var c = i as IControl; + + if (c?.IsInitialized == false) + { + var init = c as ISupportInitialize; + + if (init != null) + { + init.BeginInit(); + init.EndInit(); + } + } + } + } + + if (!IsArrangeValid) + { + Measure(Size.Infinity); + Arrange(new Rect(DesiredSize)); + } + } + } + /// /// Adds a pseudo-class to be set when a property is true. /// diff --git a/src/Avalonia.Visuals/Avalonia.Visuals.csproj b/src/Avalonia.Visuals/Avalonia.Visuals.csproj index 10074c5026..21978720e9 100644 --- a/src/Avalonia.Visuals/Avalonia.Visuals.csproj +++ b/src/Avalonia.Visuals/Avalonia.Visuals.csproj @@ -119,6 +119,7 @@ + diff --git a/src/Avalonia.Visuals/Rendering/IVisualBrushInitialize.cs b/src/Avalonia.Visuals/Rendering/IVisualBrushInitialize.cs new file mode 100644 index 0000000000..b3209e2462 --- /dev/null +++ b/src/Avalonia.Visuals/Rendering/IVisualBrushInitialize.cs @@ -0,0 +1,20 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; +using Avalonia.Media; + +namespace Avalonia.Rendering +{ + /// + /// Internal interface for initializing controls that are to be used as the viusal in a + /// . + /// + public interface IVisualBrushInitialize + { + /// + /// Ensures that the control is ready to use as the visual in a visual brush. + /// + void EnsureInitialized(); + } +} diff --git a/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs b/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs index 33d0ee258c..6c410587fe 100644 --- a/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/IVisualBrushRenderer.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; using Avalonia.Media; namespace Avalonia.Rendering @@ -8,6 +11,14 @@ namespace Avalonia.Rendering /// public interface IVisualBrushRenderer { + /// + /// Gets the size of the intermediate render target to which the visual brush should be + /// drawn. + /// + /// The visual brush. + /// The size of the intermediate render target to create. + Size GetRenderTargetSize(VisualBrush brush); + /// /// Renders a visual brush to a bitmap. /// diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 9edb0251e6..bcd84682be 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -79,6 +79,12 @@ namespace Avalonia.Rendering { } + Size IVisualBrushRenderer.GetRenderTargetSize(VisualBrush brush) + { + (brush.Visual as IVisualBrushInitialize)?.EnsureInitialized(); + return brush.Visual?.Bounds.Size ?? Size.Empty; + } + void IVisualBrushRenderer.RenderVisualBrush(IDrawingContextImpl context, VisualBrush brush) { var visual = brush.Visual; diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 6660dd1ccb..9f3360155b 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -348,24 +348,27 @@ namespace Avalonia.Direct2D1.Media { if (_visualBrushRenderer != null) { - TileBrushImplHelper.EnsureInitialized(visualBrush.Visual); + var intermediateSize = _visualBrushRenderer.GetRenderTargetSize(visualBrush); - using (var intermediate = new BitmapRenderTarget( - _renderTarget, - CompatibleRenderTargetOptions.None, - visualBrush.Visual.Bounds.Size.ToSharpDX())) + if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1) { - using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(_visualBrushRenderer)) + using (var intermediate = new BitmapRenderTarget( + _renderTarget, + CompatibleRenderTargetOptions.None, + intermediateSize.ToSharpDX())) { - intermediate.Clear(null); - _visualBrushRenderer.RenderVisualBrush(ctx, visualBrush); + using (var ctx = new RenderTarget(intermediate).CreateDrawingContext(_visualBrushRenderer)) + { + intermediate.Clear(null); + _visualBrushRenderer.RenderVisualBrush(ctx, visualBrush); + } + + return new ImageBrushImpl( + visualBrush, + _renderTarget, + new D2DBitmapImpl(intermediate.Bitmap), + destinationSize); } - - return new ImageBrushImpl( - visualBrush, - _renderTarget, - new D2DBitmapImpl(intermediate.Bitmap), - destinationSize); } } else @@ -373,10 +376,8 @@ namespace Avalonia.Direct2D1.Media throw new NotSupportedException("No IVisualBrushRenderer was supplied to DrawingContextImpl."); } } - else - { - return new SolidColorBrushImpl((Avalonia.Media.SolidColorBrush)null, _renderTarget); - } + + return new SolidColorBrushImpl(null, _renderTarget); } public void PushGeometryClip(Avalonia.Media.Geometry clip)