I am using an Adorner
to create an overlay when a button is clicked. This overlay contains a form, e.g. a login-form based on other UIElement
s (Button
, TextBox
etc.).
Basically this is how it's done: Click
But there is one problem. The overlay should fill the available space. So I set the Vertical-
/HorizontalAlignment
property of the Form's Panel (which is the Child of the ControlAdorner
) to Stretch
. However it only takes as much space as needed to show the Panel instead of using the whole available space.
I think this is why:
The ControlAdorner
's method MeasureOverride
is called with the correct size (the available space). But then the Child's Measure
-method is used to calculate the desired size. And that call seems to ignore the Stretch
property. Probably because the Child has no Parent
set, because the Child is generated dynamically.
Is there a way to achieve this Stretch
-thing for the Adorner
's Child to work properly?
I got it working :-)
Since the Adorner
s MeasureOverride
already computes the correct dimensions for overlaying the adorned element we don't need to override it. However we need to override ArrangeOverride
because we need to call the Arrange
method of the child. Otherwise it may not be shown.
So here's a working example code:
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace AdornerTest {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e) {
StackPanel overlayPanel = new StackPanel() {
Background = new SolidColorBrush(Color.FromArgb(0x99, 0, 0, 0xFF)),
};
// example content 1
Rectangle overlayChild1 = new Rectangle() {
Fill = new SolidColorBrush(Color.FromArgb(0xFF, 0xFF, 0xFF, 0xFF)),
Margin = new Thickness(10),
Height = 50,
};
overlayPanel.Children.Add(overlayChild1);
// example content 2
Button overlayChild2 = new Button();
overlayChild2.Content = "asdasd";
overlayChild2.Margin = new Thickness(10);
overlayPanel.Children.Add(overlayChild2);
OverlayAdorner adorner = new OverlayAdorner(mainGrid) {
Content = overlayPanel,
};
AdornerLayer.GetAdornerLayer(mainGrid).Add(adorner);
}
}
class OverlayAdorner : Adorner {
private FrameworkElement _content;
public OverlayAdorner(UIElement adornedElement)
: base(adornedElement) {
}
protected override int VisualChildrenCount {
get {
return _content == null ? 0 : 1;
}
}
protected override Visual GetVisualChild(int index) {
if (index != 0) throw new ArgumentOutOfRangeException();
return _content;
}
public FrameworkElement Content {
get { return _content; }
set {
if (_content != null) {
RemoveVisualChild(_content);
}
_content = value;
if (_content != null) {
AddVisualChild(_content);
}
}
}
protected override Size ArrangeOverride(Size finalSize) {
_content.Arrange(new Rect(new Point(0, 0), finalSize));
return base.ArrangeOverride(finalSize);
}
}
}
MainWindow.xaml
<Window x:Class="AdornerTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<AdornerDecorator>
<Grid Name="mainGrid">
<Button Content="Show Overlay" Name="button" VerticalAlignment="Top" Click="button_Click" />
</Grid>
</AdornerDecorator>
</Window>