UWP - Как создать CompositionSurfaceBrush с повторяющимся узором - PullRequest
0 голосов
/ 12 марта 2019

Я хотел бы иметь панель с фоном, который показывает повторяющийся узор (например, точки, равномерно разделенные на 30 пикселей).

До сих пор мне удалось создать подкласс XamlCompositionBrushBase, который позволяет намсоздать свою собственную форму (например, одну точку).но я не понимаю, как повторить этот шаблон.

Это моя специальная кисть:

public sealed class DottedBackgroundBrush : XamlCompositionBrushBase
{
    public DottedBackgroundBrush()
    {
    }

    protected override void OnConnected()
    {
        // Delay creating composition resources until they're required.
        if (CompositionBrush == null)
        {
            var compositor = Window.Current.Compositor;

            // Actual Width/Height are going to be returned in effective pixels which
            // is going to differ from the size of the bitmap that we'll render from the XAML.
            var width = 400; 
            var height = 400; 

            // Make our visual:
            var spriteVisual = compositor.CreateSpriteVisual();
            spriteVisual.Size = new Vector2(width, height);

            CanvasDevice device = CanvasDevice.GetSharedDevice();
            var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(compositor, device);
            CompositionSurfaceBrush drawingBrush = compositor.CreateSurfaceBrush();
            var drawingSurface = graphicsDevice.CreateDrawingSurface(
                new Size(width, height),
                DirectXPixelFormat.B8G8R8A8UIntNormalized,
                DirectXAlphaMode.Premultiplied);
            using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
            {
                ds.Clear(Colors.Transparent);
                ds.DrawCircle(new Vector2(10, 10), 5, Colors.Black, 3);
            }

            drawingBrush.Surface = drawingSurface;

            CompositionBrush = drawingBrush;
        }
    }

    protected override void OnDisconnected()
    {
        // Dispose of composition resources when no longer in use.
        if (CompositionBrush != null)
        {
            CompositionBrush.Dispose();
            CompositionBrush = null;
        }
    }
}

Как я могу разрешить бесконечную репликацию круга, вместо того, чтобы иметь один экземпляр

1 Ответ

1 голос
/ 12 марта 2019

Для этого вы хотите создать CompositionEffectBrush в качестве основной кисти, используя Win2D BorderEffect - который выполняет фактическое разбиение на листы - и установить его источник в качестве SurfaceBrush.

Пример (адаптировано из репо моего, так что это может быть немного окольными)

public class TilingBrush : XamlCompositionBrushBase
{
    protected Compositor _compositor => Window.Current.Compositor;

    protected CompositionBrush _imageBrush = null;

    protected IDisposable _surfaceSource = null;

    protected override void OnConnected()
    {
        base.OnConnected();

        if (CompositionBrush == null)
        {
            CreateEffectBrush();
            Render();
        }
    }

    protected override void OnDisconnected()
    {
        base.OnDisconnected();

        this.CompositionBrush?.Dispose();
        this.CompositionBrush = null;

        ClearResources();
    }

    private void ClearResources()
    {
        _imageBrush?.Dispose();
        _imageBrush = null;

        _surfaceSource?.Dispose();
        _surfaceSource = null;
    }

    private void UpdateBrush()
    {
        if (CompositionBrush != null && _imageBrush != null)
        {
            ((CompositionEffectBrush)CompositionBrush).SetSourceParameter(nameof(BorderEffect.Source), _imageBrush);
        }
    }

    protected ICompositionSurface CreateSurface()
    {
        double width = 20;
        double height = 20;

        CanvasDevice device = CanvasDevice.GetSharedDevice();
        var graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, device);
        var drawingSurface = graphicsDevice.CreateDrawingSurface(
            new Size(width, height),
            DirectXPixelFormat.B8G8R8A8UIntNormalized,
            DirectXAlphaMode.Premultiplied);

        /* Create Drawing Session is not thread safe - only one can ever be active at a time per app */
        using (var ds = CanvasComposition.CreateDrawingSession(drawingSurface))
        {
            ds.Clear(Colors.Transparent);
            ds.DrawCircle(new Vector2(10, 10), 5, Colors.Black, 3);
        }

        return drawingSurface;
    }

    private void Render()
    {
        ClearResources();

        try
        {
            var src = CreateSurface();
            _surfaceSource = src as IDisposable;
            var surfaceBrush = _compositor.CreateSurfaceBrush(src);
            surfaceBrush.VerticalAlignmentRatio = 0.0f;
            surfaceBrush.HorizontalAlignmentRatio = 0.0f;
            surfaceBrush.Stretch = CompositionStretch.None;
            _imageBrush = surfaceBrush;

            UpdateBrush();
        }
        catch
        {
            // no image for you, soz.
        }
    }

    private void CreateEffectBrush()
    {
        using (var effect = new BorderEffect
        {
            Name = nameof(BorderEffect),
            ExtendY = CanvasEdgeBehavior.Wrap,
            ExtendX = CanvasEdgeBehavior.Wrap,
            Source = new CompositionEffectSourceParameter(nameof(BorderEffect.Source))
        })
        using (var _effectFactory = _compositor.CreateEffectFactory(effect))
        {               
            this.CompositionBrush = _effectFactory.CreateBrush();
        }
    }
}

Долгое время я хотел добавить его в WindowsCommunityToolkit, но долгое время я сталкивался с ошибками с помощью визуального слоя, которые меня останавливали. Однако этот конкретный случай должен работать нормально.

...