Here is the implementation solving my problem based on the suggestions from XAML Lover and Marat Khasanov. The TestCustomControl places 2 TextBoxes diagonally of each other. The one on the top right uses as much width as needed and as much height as possible. The one on the bottom left uses as much height as needed and as much width as possible.
+------------+--------+
| | |
| |TextBox1|
| | |
+------------+--------+
| TextBox2 | |
+------------+--------+
This kind of arrangement is a problem for a Grid, because to measure the size of one TextBox it needs to know the size of the other TextBox, which is not possible. The Grid solves this dilemma by measuring first one TextBox using indefinite space, then measures the other TextBox using the size from the first one and then measures the first one again using the size of the second. This leads to all kinds of problems, which the TestCustomControl prevents completely.
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace TestControl {
public class TestCustomControl: Control {
VisualCollection visualCollection;
Rectangle RectangleToLeft;
TextBox TextBoxTopRight;
TextBox TextBoxBottomLeft;
Rectangle RectangleBottomRight;
public TestCustomControl() {
RectangleToLeft = new Rectangle { Fill = Brushes.LightYellow };
TextBoxTopRight = new TextBox {Text = "TR", FontSize = 22, HorizontalAlignment=HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch };
TextBoxBottomLeft = new TextBox {Text = "BL", FontSize = 22, HorizontalAlignment=HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Center };
RectangleBottomRight = new Rectangle {Fill = Brushes.LightBlue };
//new UIElementCollection(this, logicalParent);
visualCollection = new VisualCollection(this);
visualCollection.Add(RectangleToLeft);
visualCollection.Add(TextBoxTopRight);
visualCollection.Add(TextBoxBottomLeft);
visualCollection.Add(RectangleBottomRight);
}
protected override int VisualChildrenCount {
get {
return visualCollection.Count;
}
}
protected override System.Windows.Media.Visual GetVisualChild(int index) {
return visualCollection[index];
}
protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) {
TextBoxTopRight.Measure(constraint);
TextBoxBottomLeft.Measure(constraint);
Size returnedSize = constraint;
if (double.IsInfinity(constraint.Height)) {
returnedSize.Height = TextBoxTopRight.DesiredSize.Height + TextBoxBottomLeft.DesiredSize.Height;
}
if (double.IsInfinity(constraint.Width)) {
returnedSize.Width = TextBoxTopRight.DesiredSize.Width + TextBoxBottomLeft.DesiredSize.Width;
}
return constraint;
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeBounds) {
double remainingWidth = Math.Max(0, arrangeBounds.Width - TextBoxTopRight.DesiredSize.Width);
double remainingHeight = Math.Max(0, arrangeBounds.Height - TextBoxBottomLeft.DesiredSize.Height);
RectangleToLeft.Arrange(new Rect(0, 0, remainingWidth, remainingHeight));
TextBoxTopRight.Arrange(new Rect(remainingWidth, 0, TextBoxTopRight.DesiredSize.Width, remainingHeight));
TextBoxBottomLeft.Arrange(new Rect(0, remainingHeight, remainingWidth, TextBoxBottomLeft.DesiredSize.Height));
RectangleBottomRight.Arrange(new Rect(remainingWidth, remainingHeight, TextBoxTopRight.DesiredSize.Width, TextBoxTopRight.DesiredSize.Height));
return arrangeBounds;
}
protected override Geometry GetLayoutClip(Size layoutSlotSize) {
if (ClipToBounds)
return new RectangleGeometry(new Rect(RenderSize));
else
return null;
}
}
}