Search code examples
c#wpfoverlayloadingadorner

WPF Loading Overlay using Adorners


I want to create an easy-to-use Loading overlay. For this I wanted to use Adorners. The problem is: I want to show a progress-circle. For this I need a control.

I tried to render the control, but I can't see anything:

        protected override void OnRender(DrawingContext drawingContext)
    {
        Size parentSize = this.AdornedElement.DesiredSize;

        drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb((byte)(255 * 0.30), 0, 0, 0)), null,
            new Rect(0, 0, parentSize.Width, parentSize.Height));

        RenderTargetBitmap target = new RenderTargetBitmap(50, 50, 96, 96,
            PixelFormats.Pbgra32);
        target.Render(_ring);
        drawingContext.DrawImage(target,
            new Rect(parentSize.Width / 2 - target.Width / 2, parentSize.Height / 2 - target.Height / 2, target.Width, target.Height));

        double textUpperPos = parentSize.Height / 2 + target.Height / 2 + 10;
        target = new RenderTargetBitmap((int)parentSize.Width - 30, (int)parentSize.Height - (int)textUpperPos - 10, 96, 96,
            PixelFormats.Pbgra32);
        drawingContext.DrawImage(target,
            new Rect(parentSize.Width / 2 - target.Width / 2, textUpperPos, target.Width, target.Height));
    }

The gray background is visible, but none of the controls (TextBlock & ProgressCircle). Is this even possible using this method? Is there a better way?

I want an overlay which can be applied with max. 1-3 lines of code. Non-XAML.

Thanks :)


Solution

  • I recently found an article which was nearly not able to find via Google. It showed how to solve this problem (non-XAML way):

    You have to use VisualCollection and ContentPresenter. Some minor additions and it work's perfect.

            public LoadingAdorner(UIElement adornedElement)
            : base(adornedElement)
        {
            if (DesignerProperties.GetIsInDesignMode(this)) return;
    
            _visuals = new VisualCollection(this);
            _contentPresenter = new ContentPresenter();
            _visuals.Add(_contentPresenter);
    
            _grid = new Grid
            {
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch
            };
            _contentPresenter.Content = _grid; // Or the single control you want to display
    
            // Add your controls here to grid
        }
    
        protected override int VisualChildrenCount
        {
            get { return _visuals.Count; }
        }
    
        protected override Visual GetVisualChild(int index)
        {
            return _visuals[index];
        }
    
        protected override Size MeasureOverride(Size constraint)
        {
            _contentPresenter.Measure(constraint);
            return _contentPresenter.DesiredSize;
        }
    
        protected override Size ArrangeOverride(Size finalSize)
        {
            _contentPresenter.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height));
            return _contentPresenter.RenderSize;
        }