WPF не поддерживает это напрямую, но его достаточно легко реализовать с помощью свойств зависимости и присоединенных свойств. Сначала вам понадобится класс для вашего AreaDefinition:
public class AreaDefinition : DependencyObject
{
public int Row
{
get { return (int)GetValue(RowProperty); }
set { SetValue(RowProperty, value); }
}
public static readonly DependencyProperty RowProperty =
DependencyProperty.Register("Row", typeof(int), typeof(AreaDefinition), new PropertyMetadata(0));
public int Column
{
get { return (int)GetValue(ColumnProperty); }
set { SetValue(ColumnProperty, value); }
}
public static readonly DependencyProperty ColumnProperty =
DependencyProperty.Register("Column", typeof(int), typeof(AreaDefinition), new PropertyMetadata(0));
public int RowSpan
{
get { return (int)GetValue(RowSpanProperty); }
set { SetValue(RowSpanProperty, value); }
}
public static readonly DependencyProperty RowSpanProperty =
DependencyProperty.Register("RowSpan", typeof(int), typeof(AreaDefinition), new PropertyMetadata(1));
public int ColumnSpan
{
get { return (int)GetValue(ColumnSpanProperty); }
set { SetValue(ColumnSpanProperty, value); }
}
public static readonly DependencyProperty ColumnSpanProperty =
DependencyProperty.Register("ColumnSpan", typeof(int), typeof(AreaDefinition), new PropertyMetadata(1));
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(AreaDefinition), new PropertyMetadata(String.Empty));
}
Вам также понадобится класс для хранения их коллекции, во многом так же, как Grid.Columns является коллекцией типа ColumnDefinitionCollection:
public class AreaDefinitionCollection : Collection<AreaDefinition>
{
}
Наконец, вам понадобится класс для ваших прикрепленных свойств, который я назову GridHelper. Этот класс должен будет предоставить две точки доступа, одну для ваших гридов (GridHelper.AreaDefinitions
), а другую для дочерних гридов (GridHelper.Area
). Обработчик изменений для GridHelper.AreaProperty
- это то место, где происходят все маги c, он просто обновляет связанные Grid
AP всякий раз, когда изменяется Area:
public static class GridHelper
{
public static AreaDefinitionCollection GetAreaDefinitions(DependencyObject obj)
{
return (AreaDefinitionCollection)obj.GetValue(AreaDefinitionsProperty);
}
public static void SetAreaDefinitions(DependencyObject obj, AreaDefinitionCollection value)
{
obj.SetValue(AreaDefinitionsProperty, value);
}
public static readonly DependencyProperty AreaDefinitionsProperty =
DependencyProperty.RegisterAttached("AreaDefinitions", typeof(AreaDefinitionCollection), typeof(Grid), new PropertyMetadata(new AreaDefinitionCollection()));
public static string GetArea(DependencyObject obj)
{
return (string)obj.GetValue(AreaProperty);
}
public static void SetArea(DependencyObject obj, string value)
{
obj.SetValue(AreaProperty, value);
}
public static readonly DependencyProperty AreaProperty =
DependencyProperty.RegisterAttached("Area", typeof(string), typeof(UIElement), new PropertyMetadata(String.Empty, OnAreaChanged));
private static void OnAreaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement child = d as UIElement;
if (child == null)
return;
Grid grid = VisualTreeHelper.GetParent(child) as Grid;
if (grid == null)
return;
AreaDefinitionCollection areas = GetAreaDefinitions(grid);
if (areas == null)
return;
// the performance of this bit could be improved by giving AreaDefinitionCollection a hash table implementation, oh well.
var areaDefinition = areas.FirstOrDefault(a => a.Name == e.NewValue.ToString());
if (areaDefinition == null)
return;
// update the grid elements
Grid.SetRow(child, areaDefinition.Row);
Grid.SetRowSpan(child, areaDefinition.RowSpan);
Grid.SetColumn(child, areaDefinition.Column);
Grid.SetColumnSpan(child, areaDefinition.ColumnSpan);
}
}
С его помощью вы можете реализовать функциональность, которую вы После, с небольшими изменениями:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<g:GridHelper.AreaDefinitions>
<g:AreaDefinition Row="0" Column="0" ColumnSpan="2" Name="Header" />
<g:AreaDefinition Row="1" Column="0" Name="Navigation" />
<g:AreaDefinition Row="1" Column="1" Name="Main" />
<g:AreaDefinition Row="2" Column="0" ColumnSpan="2" Name="Footer" />
</g:GridHelper.AreaDefinitions>
<TextBlock g:GridHelper.Area="Header" Text="Header" />
<TextBlock g:GridHelper.Area="Navigation" Text="Navigation" />
<TextBlock g:GridHelper.Area="Main" Text="Main" />
<TextBlock g:GridHelper.Area="Footer" Text="Footer" />
</Grid>
Если вам не нравится префикс пространства имен g:
, вы можете избавиться от него, как указано в этой статье , добавив в файл AssemblyInfo.cs следующую строку:
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "YourGridHelperNamespace")]