This example demonstrates how to extend the LayoutControl and LayoutGroup behavior to support proportional resizing. The created LayoutItemSize
property allows you to specify relative (star *
) values.
Note
This custom solution may not support all possible usage scenarios and configurations. If proportional resizing is required, we recommend that you use controls that support this functionality out of the box (DockLayoutManager with layout groups and items or a standard Grid).
Files to Review
- ExtraLayoutControl.cs (VB: ExtraLayoutControl.vb)
- ExtraLayoutGroup.cs (VB: ExtraLayoutGroup.vb)
- MainWindow.xaml (VB: MainWindow.xaml)
Documentation
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using DevExpress.Xpf.LayoutControl;
namespace DXSample {
public class ExtraLayoutControl : DevExpress.Xpf.LayoutControl.LayoutControl {
protected override Size OnMeasure(Size constraint) {
if (constraint.Width == 0 &&
constraint.Height == 0)
return base.OnMeasure(constraint);
Size maxConstraint = new Size(Double.PositiveInfinity, Double.PositiveInfinity);
Size defaultConstraint = constraint;
constraint = base.OnMeasure(constraint);
if (Double.IsInfinity(defaultConstraint.Width) && Orientation == Orientation.Horizontal)
defaultConstraint.Width = constraint.Width;
if (Double.IsInfinity(defaultConstraint.Height) && Orientation == Orientation.Vertical)
defaultConstraint.Height = constraint.Height;
double starCount = 0;
#region Create GroupLists
List<ExtraLayoutGroup> listPixel = new List<ExtraLayoutGroup>();
List<ExtraLayoutGroup> listStar = new List<ExtraLayoutGroup>();
foreach (UIElement child in Children) {
if (child is ExtraLayoutGroup) {
if (((ExtraLayoutGroup)child).LayoutItemSize.Value > 0)
switch (((ExtraLayoutGroup)child).LayoutItemSize.GridUnitType) {
case GridUnitType.Pixel:
listPixel.Add((ExtraLayoutGroup)child);
break;
case GridUnitType.Star:
listStar.Add((ExtraLayoutGroup)child);
starCount += ((ExtraLayoutGroup)child).LayoutItemSize.Value;
break;
}
}
}
if (listPixel.Count == 0 && listStar.Count == 0)
return constraint;
#endregion
#region Resize Pixeled
foreach (ExtraLayoutGroup group in listPixel) {
if (Orientation == Orientation.Horizontal)
group.Width = group.LayoutItemSize.Value;
else
group.Height = group.LayoutItemSize.Value;
group.InvalidateMeasure();
group.Measure((Orientation == Orientation.Horizontal) ? new Size(group.LayoutItemSize.Value, maxConstraint.Height) :
new Size(maxConstraint.Width, group.LayoutItemSize.Value));
}
#endregion
constraint = base.OnMeasure(defaultConstraint);
if (starCount == 0)
return constraint;
double starSize = 0;
#region Calc StarSize
Double usedSize = (Orientation == Orientation.Horizontal) ? constraint.Width : constraint.Height;
foreach (ExtraLayoutGroup group in listStar)
usedSize -= (Orientation == Orientation.Horizontal) ? group.DesiredSize.Width : group.DesiredSize.Height;
Double availableSize = ((Orientation == Orientation.Horizontal) ? defaultConstraint.Width :
defaultConstraint.Height) - usedSize;
starSize = availableSize / starCount;
#endregion
#region Resize Starred
foreach (ExtraLayoutGroup group in listStar) {
if (Orientation == Orientation.Horizontal)
group.Width = group.LayoutItemSize.Value * starSize;
else
group.Height = group.LayoutItemSize.Value * starSize;
group.InvalidateMeasure();
group.Measure((Orientation == Orientation.Horizontal) ? new Size(group.Width, maxConstraint.Height) :
new Size(maxConstraint.Width, group.Height));
}
#endregion
return base.OnMeasure(constraint);
}
}
}
C#using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using DevExpress.Xpf.LayoutControl;
using System.Windows.Controls;
namespace DXSample {
public class ExtraLayoutGroup : LayoutGroup {
public GridLength LayoutItemSize {
get { return (GridLength)GetValue(LayoutItemSizeProperty); }
set { SetValue(LayoutItemSizeProperty, value); }
}
public static readonly DependencyProperty LayoutItemSizeProperty =
DependencyProperty.Register("LayoutItemSize", typeof(GridLength), typeof(ExtraLayoutGroup), new PropertyMetadata(new GridLength(0, GridUnitType.Star)));
protected override Size OnMeasure(Size constraint) {
if (constraint.Width == 0 &&
constraint.Height == 0)
return base.OnMeasure(constraint);
Size maxConstraint = new Size(Double.PositiveInfinity, Double.PositiveInfinity);
Size defaultConstraint = constraint;
constraint = base.OnMeasure(constraint);
Size minConstraint = new Size(Math.Min(defaultConstraint.Width, constraint.Width),
Math.Min(defaultConstraint.Height, constraint.Height));
double starCount = 0;
#region Create GroupLists
List<ExtraLayoutGroup> listPixel = new List<ExtraLayoutGroup>();
List<ExtraLayoutGroup> listStar = new List<ExtraLayoutGroup>();
foreach (UIElement child in Children) {
if (child is ExtraLayoutGroup) {
ExtraLayoutGroup group = (ExtraLayoutGroup)child;
if (Parent is ExtraLayoutControl) {
switch (((ExtraLayoutControl)Parent).Orientation) {
case Orientation.Horizontal:
((FrameworkElement)child).HorizontalAlignment = HorizontalAlignment.Stretch;
break;
case Orientation.Vertical:
((FrameworkElement)child).VerticalAlignment = VerticalAlignment.Stretch;
break;
}
}
if (Parent is ExtraLayoutGroup) {
switch (((ExtraLayoutGroup)Parent).Orientation) {
case Orientation.Horizontal:
((FrameworkElement)child).HorizontalAlignment = HorizontalAlignment.Stretch;
break;
case Orientation.Vertical:
((FrameworkElement)child).VerticalAlignment = VerticalAlignment.Stretch;
break;
}
}
if (group.LayoutItemSize.Value > 0)
switch (group.LayoutItemSize.GridUnitType) {
case GridUnitType.Pixel:
listPixel.Add((ExtraLayoutGroup)child);
break;
case GridUnitType.Star:
listStar.Add((ExtraLayoutGroup)child);
starCount += ((ExtraLayoutGroup)child).LayoutItemSize.Value;
break;
}
}
}
if (listPixel.Count == 0 && listStar.Count == 0)
return constraint;
#endregion
#region Resize Pixeled
foreach (ExtraLayoutGroup group in listPixel) {
if (Orientation == Orientation.Horizontal)
group.Width = group.LayoutItemSize.Value;
else
group.Height = group.LayoutItemSize.Value;
group.InvalidateMeasure();
group.Measure(minConstraint);
}
#endregion
constraint = base.OnMeasure(minConstraint);
minConstraint.Width = Math.Min(minConstraint.Width, constraint.Width);
minConstraint.Height = Math.Min(minConstraint.Height, constraint.Height);
if (starCount == 0)
return minConstraint;
double starSize = 0;
#region Calc StarSize
Double usedSize = (Orientation == Orientation.Horizontal) ? constraint.Width : constraint.Height;
foreach (ExtraLayoutGroup group in listStar)
usedSize -= (Orientation == Orientation.Horizontal) ? group.DesiredSize.Width : group.DesiredSize.Height;
Double availableSize = ((Orientation == Orientation.Horizontal) ? minConstraint.Width :
minConstraint.Height) - usedSize;
starSize = availableSize / starCount;
#endregion
#region Resize Starred
foreach (ExtraLayoutGroup group in listStar) {
if (Orientation == Orientation.Horizontal)
group.Width = group.LayoutItemSize.Value * starSize;
else
group.Height = group.LayoutItemSize.Value * starSize;
group.InvalidateMeasure();
group.Measure((Orientation == Orientation.Horizontal) ? new Size(group.Width, minConstraint.Height) :
new Size(minConstraint.Width, group.Height));
}
#endregion
return base.OnMeasure(minConstraint);
}
}
}
XAML<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
xmlns:DXSample="clr-namespace:DXSample"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" x:Class="LayoutControl.MainWindow"
Title="MainWindow"
Height="356" Width="636">
<Grid>
<Border BorderBrush="Black" BorderThickness="1" Margin="10">
<DXSample:ExtraLayoutControl Orientation="Horizontal" UseLayoutRounding="True">
<DXSample:ExtraLayoutGroup Orientation="Vertical" LayoutItemSize="2*">
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="Tabs" LayoutItemSize="1*"/>
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="GroupBox" LayoutItemSize="30"/>
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="GroupBox" LayoutItemSize="4*"/>
</DXSample:ExtraLayoutGroup>
<DXSample:ExtraLayoutGroup Orientation="Horizontal" LayoutItemSize="1*">
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="Tabs" Orientation="Vertical">
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="Group"/>
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="Group"/>
</DXSample:ExtraLayoutGroup>
<dxlc:LayoutGroup Header="LayoutGroup" View="Tabs"/>
</DXSample:ExtraLayoutGroup>
<DXSample:ExtraLayoutGroup Header="LayoutGroup" View="GroupBox" LayoutItemSize="30"/>
</DXSample:ExtraLayoutControl>
</Border>
</Grid>
</Window>