Динамическое изменение размера открытого Аккордеона
У меня есть Аккордеон, а высота его содержимого может быть динамически изменена. Я хотел бы видеть, как Аккордеон динамически реагирует на рост дочернего элемента, но у меня возникают проблемы с этим.
<lt:Accordion Name="MyAccordion"
SelectionMode="ZeroOrOne"
HorizontalAlignment="Stretch">
<lt:AccordionItem Name="MyAccordionItem"
Header="MyAccordion"
IsSelected="True"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch">
<StackPanel>
<Button Content="Grow" Click="Grow"/>
<Button Content="Shrink" Click="Shrink"/>
<TextBox Name="GrowTextBox"
Text="GrowTextBox"
Height="400"
Background="Green"
SizeChanged="GrowTextBox_SizeChanged"/>
</StackPanel>
</lt:AccordionItem>
</lt:Accordion>
private void Grow(object sender, System.Windows.RoutedEventArgs e)
{
GrowTextBox.Height += 100;
}
private void Shrink(object sender, System.Windows.RoutedEventArgs e)
{
GrowTextBox.Height -= 100;
}
private void GrowTextBox_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
MyAccordion.UpdateLayout();
MyAccordionItem.UpdateLayout();
}
Имейте в виду, что если я рухну, а затем снова открою аккордеон, он приобретет форму именно так, как я хочу, но я бы хотел, чтобы это изменение размера происходило сразу же, когда ребенок изменяет размеры.
Я слабо попытался исправить это, добавив обработчик события SizeChanged, который вызывает UpdateLayout() для Accordion и AccordionItem, но это не имеет никакого визуального эффекта. Я не могу понять, где происходит правильное изменение размера внутри элемента управления Accordion. У кого-нибудь есть идея?
3 ответа
Попробуй это
//here i am creating a size object depending on child items height and width
// and 25 for accordian item header...
// if it works you can easily update the following code to avoid exceptional behaviour
Size size = new Size();
size.Width = GrowTextBox.ActualWidth;
size.Height = grow.ActualHeight + shrink.ActualHeight + GrowTextBox.ActualHeight + 25;
MyAccordion.Arrange(new Rect(size));
В приведенном выше коде я просто переставляю аккордеон в зависимости от размера дочернего элемента.
У меня была немного другая проблема - изменение размера моего окна иногда неправильно корректировало размер элемента Accordion, поэтому заголовок следующего элемента застревал под окном или в середине его.
Я решил эту проблему, создав таймер, который запускается в SizeChanged и отменяет выбор и сразу же повторно выбирает текущий элемент, после чего макет кажется перенастроенным и корректным. Может помочь и тебе. Вы можете обойтись без таймера, я ввел его для предотвращения непрерывных звонков, когда пользователь перетаскивает размер окна, он также дает некоторый пернатый эффект из-за задержки.
public partial class MyAccordion : System.Windows.Controls.Accordion
{
private Timer _layoutUpdateTimer = new Timer(100);
public MyAccordion
{
this.SizeChanged += (s, e) =>
{
_layoutUpdateTimer.Stop(); // prevents continuous calls
_layoutUpdateTimer.Start();
};
_layoutUpdateTimer.Elapsed += (s, e) => ReselectItem();
}
private void ReselectItem()
{
Application.Current.Dispatcher.BeginInvoke((Action)(() =>
{
// backup values
int selectedIndex = this.SelectedIndex;
AccordionSelectionMode mode = this.SelectionMode;
// deselect
this.SelectionMode = AccordionSelectionMode.ZeroOrOne; // allow null selection
this.SelectedItem = null;
// restore values (reselect)
this.SelectionMode = mode;
this.SelectedIndex = selectedIndex;
}));
_layoutUpdateTimer.Stop();
}
}
У меня похожая проблема, мой простой взлом заключается в следующем:
private void GrowTextBox_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
MyAccordionItem.Measure(new Size());
MyAccordionItem.UpdateLayout();
}
Надеюсь, что это работает для вас тоже..
ура