В моем приложении Silverlight есть экран меню с кнопками. Для этого я использую ItemsControl с WrapPanel в качестве шаблона ItemsPanel, поэтому кнопки переносятся на следующую строку (как текстовое поле с текстом).
Меню примерно такое:
Теперь мне нужна новая функция: сгруппировать кнопки по категориям. Поэтому я решил использовать для этого Accordion с предметами ZeroOrMore. Я использую ScrollViewer как Accordion ContentTemplate с MaxHeight 150, чтобы ограничить высоту группы до 150 и использовать после этого вертикальную полосу прокрутки. Внутри ScrollViewer есть тот же ItemsControl с WrapPanel и кнопками.
Я хочу, чтобы в WrapPanel было 3 строки элементов без прокрутки, поэтому я выбрал MaxHeight = 150 не зря: каждая кнопка (с полями) имеет высоту 50. Это позволило бы иметь 3 строки без полос прокрутки. . Это прекрасно работает без аккордеона, но не работает с ним.
Проблема в том, что Accordion, похоже, не понимает высоту WrapPanel и предполагает, что он имеет высоту только 1 строки, то есть высоту 1 кнопки с полями. Итак, когда я разворачиваю элемент Accordion, он всегда имеет высоту 50. Это нормально, если у меня есть только 1 строка элементов, но если у меня 2 строки или более, высота не увеличивается до 100 или 150, она все равно 50 и полосы прокрутки появляются, так как высоты гармошки не хватает.
Вот что сейчас происходит:
Если я вручную установил ширину или высоту ScrollViewer или WrapPanel, проблемы не возникнет. Но это окно с изменяемым размером, и я не знаю его размера или сколько itens будет в каждой группе. Пользователь настраивает это, поэтому я не могу просто установить высоту или ширину. Аккордеон нужен мне, чтобы правильно рассчитать высоту.
Здесь для целей тестирования я установил ScrollViewer Width = 350 (немного меньше, чем ширина Accordion / UserControl, чтобы мы могли легко его увидеть), а также MaxHeight = 100 strong> (так что для 2-й группы этого будет мало).
На рисунке выше показано то, что я хотел, но без ширины, чтобы пользователь мог изменять размер окна и отображать больше кнопок на экране.
Когда я разворачиваю аккордеон, я замечаю, что WrapPanel настраивает кнопки динамически, поскольку я вижу, как это происходит, я вижу, как элементы переносятся от конца первой строки к следующей. Итак, я предполагаю, что перед расширением Accordion WrapPanel не имеет ширины (возможно, это бесконечность), и поэтому она еще не обернула кнопки. Он «думает», что есть место для всех элементов в первой строке.
Ниже приведено приложение Silverlight, которое я написал, чтобы показать проблему. Файл MainPage.xaml:
<ScrollViewer Padding="0" BorderThickness="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" Margin="5">
<Grid>
<toolkit:Accordion HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="10"
HorizontalContentAlignment="Left" VerticalContentAlignment="Stretch"
ItemsSource="{Binding Groups}" SelectionMode="ZeroOrMore">
<toolkit:Accordion.ItemContainerStyle>
<Style TargetType="toolkit:AccordionItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</toolkit:Accordion.ItemContainerStyle>
<toolkit:Accordion.AccordionButtonStyle>
<Style TargetType="toolkit:AccordionButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="toolkit:AccordionButton">
<Border Background="LightCyan" BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding Description}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</toolkit:Accordion.AccordionButtonStyle>
<toolkit:Accordion.ContentTemplate>
<DataTemplate>
<Grid>
<ScrollViewer MaxHeight="150" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" >
<ItemsControl ItemsSource="{Binding Items}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel HorizontalAlignment="Left" Margin="10"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button HorizontalContentAlignment="Left" Margin="3" Width="195" HorizontalAlignment="Left" VerticalAlignment="Top" Content="{Binding Description}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</DataTemplate>
</toolkit:Accordion.ContentTemplate>
</toolkit:Accordion>
</Grid>
</ScrollViewer>
И код C #: MainPage.xaml.cs с привязками свойств и кодом для добавления образцов групп / элементов:
public partial class MainPage : UserControl, INotifyPropertyChanged
{
public class ItemViewModel
{
public string Description { get; set; }
}
public class GroupViewModel
{
public List<ItemViewModel> Items { get; set; }
public string Description { get; set; }
}
public List<ItemViewModel> Items { get; set; }
public List<GroupViewModel> Groups { get; set; }
public MainPage()
{
InitializeComponent();
this.DataContext = this;
this.Groups = new List<GroupViewModel>();
GroupViewModel g1, g2, g3;
this.Groups.Add(g1 = new GroupViewModel() { Description = "Group with 4 itens", Items = new List<ItemViewModel>() });
g1.Items.Add(new ItemViewModel() { Description = "item1" } );
g1.Items.Add(new ItemViewModel() { Description = "item2" } );
g1.Items.Add(new ItemViewModel() { Description = "item3" } );
g1.Items.Add(new ItemViewModel() { Description = "item4" } );
this.Groups.Add(g2 = new GroupViewModel() { Description = "Group with 10 itens", Items = new List<ItemViewModel>() });
g2.Items.Add(new ItemViewModel() { Description = "item1" } );
g2.Items.Add(new ItemViewModel() { Description = "item2" } );
g2.Items.Add(new ItemViewModel() { Description = "item3" } );
g2.Items.Add(new ItemViewModel() { Description = "item4" } );
g2.Items.Add(new ItemViewModel() { Description = "item5" } );
g2.Items.Add(new ItemViewModel() { Description = "item6" } );
g2.Items.Add(new ItemViewModel() { Description = "item7" } );
g2.Items.Add(new ItemViewModel() { Description = "item8" } );
g2.Items.Add(new ItemViewModel() { Description = "item9" } );
g2.Items.Add(new ItemViewModel() { Description = "item10" } );
this.Groups.Add(g3 = new GroupViewModel() { Description = "Group with 3 itens", Items = new List<ItemViewModel>() });
g3.Items.Add(new ItemViewModel() { Description = "item1" } );
g3.Items.Add(new ItemViewModel() { Description = "item2" });
g3.Items.Add(new ItemViewModel() { Description = "item3" });
NotifyPropertyChanged("Groups");
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}