Skip to content

Instantly share code, notes, and snippets.

@t00
Created October 6, 2017 15:58
Show Gist options
  • Select an option

  • Save t00/e6580f260e56d09a529c53db38437cc1 to your computer and use it in GitHub Desktop.

Select an option

Save t00/e6580f260e56d09a529c53db38437cc1 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace Custom.Controls
{
public class ColumnPanel: Panel
{
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register
(
"Columns",
typeof(int),
typeof(ColumnPanel),
new FrameworkPropertyMetadata(2, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)
);
/// <summary>
/// Gets or sets the number of columns in which controls will be arranged
/// </summary>
public int Columns
{
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
}
public static readonly DependencyProperty RowSpacingProperty = DependencyProperty.Register
(
"RowSpacing",
typeof(double),
typeof(ColumnPanel),
new FrameworkPropertyMetadata(0.0d, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)
);
/// <summary>
/// Gets or sets the amount of spacing (in device independent pixels) between the rows.
/// </summary>
public double RowSpacing
{
get { return (double)GetValue(RowSpacingProperty); }
set { SetValue(RowSpacingProperty, value); }
}
public static readonly DependencyProperty ColumnSpacingProperty = DependencyProperty.Register
(
"ColumnSpacing",
typeof(double),
typeof(ColumnPanel),
new FrameworkPropertyMetadata(0.0d, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)
);
/// <summary>
/// Gets or sets the amount of spacing (in device independent pixels) between the columns.
/// </summary>
public double ColumnSpacing
{
get { return (double)GetValue(ColumnSpacingProperty); }
set { SetValue(ColumnSpacingProperty, value); }
}
public static readonly DependencyProperty StretchColumnProperty = DependencyProperty.Register
(
"StretchColumn",
typeof(int),
typeof(ColumnPanel),
new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure)
);
/// <summary>
/// Gets or sets the number of columns in which controls will be arranged
/// This is 0-based index of a column, by default set to 1 (second column)
/// </summary>
public int StretchColumn
{
get { return (int)GetValue(StretchColumnProperty); }
set { SetValue(StretchColumnProperty, value); }
}
protected override Size MeasureOverride(Size constraint)
{
double widthSoFar = 0;
columnWidths.Clear();
rowHeights.Clear();
for(var column = 0; column < Columns; column++)
{
var widthRemaining = Math.Max(0, constraint.Width - widthSoFar);
var columnConstraint = new Size(widthRemaining, constraint.Height);
double columnWidth = 0;
for(var i = column; i < VisualChildrenCount; i += Columns)
{
if(i < Children.Count)
{
var child = Children[i];
child.Measure(columnConstraint);
columnWidth = Math.Max(child.DesiredSize.Width, columnWidth);
if(column == 0)
{
rowHeights.Add(child.DesiredSize.Height);
}
else
{
rowHeights[i/Columns] = Math.Max(rowHeights[i/Columns], child.DesiredSize.Height);
}
}
}
columnWidths.Add(columnWidth);
widthSoFar += columnWidth + ColumnSpacing;
}
return new Size(Math.Max(0, widthSoFar - ColumnSpacing), Math.Max(0, rowHeights.Sum() + ((rowHeights.Count - 1) * RowSpacing)));
}
protected override Size ArrangeOverride(Size arrangeSize)
{
double x = 0;
double y = 0;
for(var i = 0; i < VisualChildrenCount; i++)
{
var child = Children[i];
var column = i % Columns;
var isLastColumn = column == Columns - 1;
var height = rowHeights[i / Columns];
var width = columnWidths[column];
if(column == StretchColumn)
{
width = Math.Max(width, arrangeSize.Width - columnWidths.Sum() + width - (ColumnSpacing * (Columns - 1)));
}
if(column == 0)
{
x = 0;
}
var r = new Rect(x, y, width, height);
child.Arrange(r);
x += width + ColumnSpacing;
if(isLastColumn)
{
y += height + RowSpacing;
}
}
return base.ArrangeOverride(arrangeSize);
}
private readonly List<double> columnWidths = new List<double>();
private readonly List<double> rowHeights = new List<double>();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment