Расширители в сетке
Это будет прямо, без сомнения, но по какой-то причине мой разум рисует пробел.
У меня есть небольшое, не изменяемое по размеру окно (325x450), в котором есть 3 экспандера, уложенных вертикально. Каждый Expander содержит элемент ItemsControl, который может иметь много элементов и, следовательно, должен прокручиваться.
То, что я не могу понять, - это как развернуть Expanders так, чтобы они расширялись, чтобы заполнить любое пространство, которое доступно, не вытесняя другие элементы с экрана. Я могу добиться того, что мне нужно, используя Grid и помещая каждый расширитель в строку с высотой *, но это означает, что они всегда занимают 1/3 окна, каждый из которых побеждает точку Expander:)
Crappy диаграмма того, чего я пытаюсь достичь:
![enter image description here]()
Ответы
Ответ 1
Если вы не против небольшого кода, вы, вероятно, можете подключиться к событиям Expanded
/Collapsed
, найти родительский Grid
, получить RowDefinition
для расширителя и установить значение равный *
, если его расширен, или Auto
, если нет.
Например,
Expander ex = sender as Expander;
Grid parent = FindAncestor<Grid>(ex);
int rowIndex = Grid.GetRow(ex);
if (parent.RowDefinitions.Count > rowIndex && rowIndex >= 0)
parent.RowDefinitions[rowIndex].Height =
(ex.IsExpanded ? new GridLength(1, GridUnitType.Star) : GridLength.Auto);
И метод FindAncestor
определяется следующим образом:
public static T FindAncestor<T>(DependencyObject current)
where T : DependencyObject
{
// Need this call to avoid returning current object if it is the
// same type as parent we are looking for
current = VisualTreeHelper.GetParent(current);
while (current != null)
{
if (current is T)
{
return (T)current;
}
current = VisualTreeHelper.GetParent(current);
};
return null;
}
Ответ 2
Это требование немного мало, потому что вы хотите, чтобы состояние Children
в Grid
определяло Height
для RowDefinition
, в котором они находятся.
Мне действительно нравится идея компоновки, хотя я не могу поверить, что у меня никогда не было такого же требования...:)
Для многоразового решения я бы использовал Attached Behavior для Grid
.
Поведение будет подписано на Attached Events Expander.Expanded
и Expander.Collapsed
, а в обработчиках событий получите RowDefinition
из Grid.GetRow
и соответствующим образом обновить Height
. Он работает следующим образом
<Grid ex:GridExpanderSizeBehavior.SizeRowsToExpanderState="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Expander Grid.Row="0" ... />
<Expander Grid.Row="1" ... />
<Expander Grid.Row="2" ... />
<!-- ... -->
</Grid>
И вот GridExpanderSizeBehavior
public class GridExpanderSizeBehavior
{
public static DependencyProperty SizeRowsToExpanderStateProperty =
DependencyProperty.RegisterAttached("SizeRowsToExpanderState",
typeof(bool),
typeof(GridExpanderSizeBehavior),
new FrameworkPropertyMetadata(false, SizeRowsToExpanderStateChanged));
public static void SetSizeRowsToExpanderState(Grid grid, bool value)
{
grid.SetValue(SizeRowsToExpanderStateProperty, value);
}
private static void SizeRowsToExpanderStateChanged(object target, DependencyPropertyChangedEventArgs e)
{
Grid grid = target as Grid;
if (grid != null)
{
if ((bool)e.NewValue == true)
{
grid.AddHandler(Expander.ExpandedEvent, new RoutedEventHandler(Expander_Expanded));
grid.AddHandler(Expander.CollapsedEvent, new RoutedEventHandler(Expander_Collapsed));
}
else if ((bool)e.OldValue == true)
{
grid.RemoveHandler(Expander.ExpandedEvent, new RoutedEventHandler(Expander_Expanded));
grid.RemoveHandler(Expander.CollapsedEvent, new RoutedEventHandler(Expander_Collapsed));
}
}
}
private static void Expander_Expanded(object sender, RoutedEventArgs e)
{
Grid grid = sender as Grid;
Expander expander = e.OriginalSource as Expander;
int row = Grid.GetRow(expander);
if (row <= grid.RowDefinitions.Count)
{
grid.RowDefinitions[row].Height = new GridLength(1.0, GridUnitType.Star);
}
}
private static void Expander_Collapsed(object sender, RoutedEventArgs e)
{
Grid grid = sender as Grid;
Expander expander = e.OriginalSource as Expander;
int row = Grid.GetRow(expander);
if (row <= grid.RowDefinitions.Count)
{
grid.RowDefinitions[row].Height = new GridLength(1.0, GridUnitType.Auto);
}
}
}