Skip to content

Instantly share code, notes, and snippets.

@mwisnicki
Created June 28, 2012 12:36
Show Gist options
  • Save mwisnicki/3011104 to your computer and use it in GitHub Desktop.
Save mwisnicki/3011104 to your computer and use it in GitHub Desktop.
[WPF] Automatic rows in Grid
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication1
{
public class AutoGrid : Grid
{
public static readonly DependencyProperty GeneratedRowStyleProperty =
DependencyProperty.Register("GeneratedRowStyle", typeof (Style), typeof (AutoGrid), new PropertyMetadata(default(Style)));
public Style GeneratedRowStyle
{
get { return (Style) GetValue(GeneratedRowStyleProperty); }
set { SetValue(GeneratedRowStyleProperty, value); }
}
public static readonly DependencyProperty GeneratedRowProperty =
DependencyProperty.RegisterAttached("GeneratedRow", typeof (int), typeof (AutoGrid), new PropertyMetadata(default(int)));
protected static void SetGeneratedRow(UIElement element, int value)
{
element.SetValue(GeneratedRowProperty, value);
}
public static int GetGeneratedRow(UIElement element)
{
return (int) element.GetValue(GeneratedRowProperty);
}
private int lastRow = 0;
protected override void OnVisualChildrenChanged(System.Windows.DependencyObject visualAdded, System.Windows.DependencyObject visualRemoved)
{
base.OnVisualChildrenChanged(visualAdded, visualRemoved);
if (visualAdded != null)
{
if (visualAdded is AutoGridEndRow)
lastRow++;
EnsureEnoughRows();
if (IsDefaultValue(visualAdded, RowProperty))
{
visualAdded.SetValue(GeneratedRowProperty, lastRow);
visualAdded.SetCurrentValue(RowProperty, lastRow);
}
var dpd = DependencyPropertyDescriptor.FromProperty(RowProperty, visualAdded.GetType());
dpd.AddValueChanged(visualAdded, OnChildRowChanged);
}
if (visualRemoved != null)
{
var dpd = DependencyPropertyDescriptor.FromProperty(RowProperty, visualAdded.GetType());
dpd.RemoveValueChanged(visualAdded, OnChildRowChanged);
}
}
private static bool IsDefaultValue(DependencyObject o, DependencyProperty property)
{
return DependencyPropertyHelper.GetValueSource(o, property).BaseValueSource == BaseValueSource.Default;
}
private void OnChildRowChanged(object sender, EventArgs ev)
{
var element = (UIElement) sender;
// Restore generated row value if row property is cleared
if (IsDefaultValue(element, RowProperty) && !IsDefaultValue(element, GeneratedRowProperty))
element.SetCurrentValue(RowProperty, GetGeneratedRow(element));
EnsureEnoughRows();
}
private void EnsureEnoughRows()
{
foreach (UIElement child in Children)
{
lastRow = Math.Max(lastRow, GetRow(child));
}
for (int i = RowDefinitions.Count; i < lastRow + 1; i++)
{
var newRow = new RowDefinition();
if (GeneratedRowStyle != null)
newRow.SetCurrentValue(StyleProperty, GeneratedRowStyle);
RowDefinitions.Add(newRow);
}
}
}
public class AutoGridEndRow : UIElement
{
public AutoGridEndRow()
{
Visibility = Visibility.Collapsed;
}
}
}
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication1"
Title="Window1"
Height="300"
Width="300">
<my:AutoGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Content="Label1" />
<TextBox Grid.Column="1" />
<my:AutoGridEndRow />
<Label Content="Label1" />
<TextBox Grid.Column="1" />
</my:AutoGrid>
</Window>
@dbenzhuser
Copy link

In lines 42 to 46 you check visualRemoved for null, but then continue to work on visualAdded. Copy & paste error or intention?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment