2016-02-02 3 views
5

Есть решения этой проблемы для старых основанных на XAML интерфейсах пользовательского интерфейса (WPF/SL), но они нелегко адаптируются к универсальной платформе Windows.Создайте ListBox с элементами, которые расширяются при выборе (Accordion)

Я пытаюсь создать список элементов, которые показывают только ограниченные детали в состоянии по умолчанию и расширяют, когда он выбран, для быстрого редактирования некоторых данных.
Я не нашел способ создать такое расширяющееся поведение, хотя оно похоже на то, что делает приложение Windows 10 Mail, с разговорами. Когда выбрано сообщение о разговоре, другие сообщения этого типа разворачиваются или спускаются вниз.

Ниже приведен пример списка, в котором я хотел бы сначала отобразить только имя.

<ListBox ItemsSource="{x:Bind Persons}"> 
    <ListBox.ItemContainerStyle> 
     <Style TargetType="ListBoxItem"> 
      <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
     </Style> 
    </ListBox.ItemContainerStyle> 
    <ListBox.ItemTemplate> 
     <DataTemplate x:DataType="src:Person"> 
      <StackPanel HorizontalAlignment="Stretch" Width="Auto"> 
       <TextBlock Text="{x:Bind Path=Name, Mode=OneWay}" Margin="12, 15, 12, 0" FontSize="18.667" /> 
       <TextBox HorizontalAlignment="Stretch" Margin="12, 12, 12, 0" FontSize="18.667" Text="{x:Bind Path=Name, Mode=TwoWay}" /> 
       <TextBlock Text="Date of birth" Margin="12, 15, 12, 0" /> 
       <DatePicker Margin="12, 5, 12, 0" Date="{x:Bind Path=DateOfBirth, Mode=TwoWay}" /> 
       <TextBlock Text="Domicile" Margin="12, 15, 12, 0" /> 
       <TextBox Margin="12, 5, 12, 0" Text="{x:Bind Path=Domicile, Mode=OneWay}" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

В WPF, такое поведение может быть достигнуто с триггерами Style.Triggers, но они больше не доступны.

Первоисточник код на GitHub

+0

У вас все еще есть триггеры, доступные вам в UWP, и есть несколько способов сделать это в чистом XAML, одним быстрым и простым способом, который я мог бы придумать. Создайте ItemTemplate со стилизованным ToggleButton и панелью под ним. Затем привяжите видимость панели к состоянию IsChecked ToggleButton и добавьте конвертер Bool to Visibility, voila, сделанный. –

ответ

0

Я создал расширяемой ListView управления для UWP - вы можете найти его here в репо GitHub. Это фактически портированная версия WPF Expander, которую я адаптировал для работы с универсальной платформой Windows.

Здесь вы можете найти мой вопрос и ответить на StackOverflow.

0

Как и Крис Саид, мы можем добавить свойство в ViewModel для управления расширяющимся поведением, но это необходимо для изменения ViewModel. Если вы не хотите этого делать, вот еще один подход:

Во-первых, нам нужны два DataTemplate, один для отображения краткой информации, а другой для отображения информации. Например:

<Page.Resources> 
    <!-- brief information template --> 
    <DataTemplate x:Key="ItemTemplate" x:DataType="src:Person"> 
     <StackPanel Width="Auto" HorizontalAlignment="Stretch"> 
      <TextBlock Margin="12, 15, 12, 0" 
         FontSize="18.667" 
         Text="{x:Bind Path=Name, Mode=OneWay}" /> 
      <TextBox Margin="12, 12, 12, 0" 
        HorizontalAlignment="Stretch" 
        FontSize="18.667" 
        Text="{x:Bind Path=Name, Mode=TwoWay}" /> 
     </StackPanel> 
    </DataTemplate> 
    <!-- details expand template --> 
    <DataTemplate x:Key="SelectedTemplate" x:DataType="src:Person"> 
     <StackPanel Width="Auto" HorizontalAlignment="Stretch"> 
      <TextBlock Margin="12, 15, 12, 0" 
         FontSize="18.667" 
         Text="{x:Bind Path=Name, Mode=OneWay}" /> 
      <TextBox Margin="12, 12, 12, 0" 
        HorizontalAlignment="Stretch" 
        FontSize="18.667" 
        Text="{x:Bind Path=Name, Mode=TwoWay}" /> 
      <StackPanel> 
       <TextBlock Margin="12, 15, 12, 0" Text="Date of birth" /> 
       <DatePicker Margin="12, 5, 12, 0" Date="{x:Bind Path=DateOfBirth, Mode=TwoWay}" /> 
       <TextBlock Margin="12, 15, 12, 0" Text="Domicile" /> 
       <TextBox Margin="12, 5, 12, 0" Text="{x:Bind Path=Domicile, Mode=OneWay}" /> 
      </StackPanel> 
     </StackPanel> 
    </DataTemplate> 
</Page.Resources> 

Затем в ListBox установить по умолчанию ItemTemplate краткими шаблон информации.

<ListBox ItemTemplate="{StaticResource ItemTemplate}" 
     ItemsSource="{x:Bind Persons}" 
     SelectionChanged="ListBox_SelectionChanged"> 
    <ListBox.ItemContainerStyle> 
     <Style TargetType="ListBoxItem"> 
      <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
     </Style> 
    </ListBox.ItemContainerStyle> 
</ListBox> 

Наконец, добавьте обработчик события к событию SelectionChanged и в этом изменении ContentTemplate обработчика для выбранного и невыбранного пункта.

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var listBox = sender as ListBox; 
    //get unselected item 
    var unselectedPerson = e.RemovedItems.FirstOrDefault() as Person; 
    if (unselectedPerson != null) 
    { 
     //get unselected item container 
     var unselectedItem = listBox.ContainerFromItem(unselectedPerson) as ListBoxItem; 
     //set ContentTemplate 
     unselectedItem.ContentTemplate = (DataTemplate)this.Resources["ItemTemplate"]; 
    } 
    //get selected item container 
    var selectedItem = listBox.ContainerFromItem(listBox.SelectedItem) as ListBoxItem; 
    selectedItem.ContentTemplate = (DataTemplate)this.Resources["SelectedTemplate"]; 
} 
0

Вот одно решение, используя MVVM:

<ListBox ItemsSource="{Binding Items}" 
     SelectedItem="{Binding SelectedItem, Mode=TwoWay}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <TextBlock Text="Title" /> 
       <TextBlock Text="Details" Visibility="{Binding IsSelected, Converter={StaticResource VisibilityConverter}}" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 
public class ViewModel : BindableBase 
{ 
    private Item _selectedItem; 


    public Item[] Items { get; } 

    public Item SelectedItem 
    { 
     get { return _selectedItem; } 
     set 
     { 
      if (_selectedItem != null) _selectedItem.IsSelected = false; 
      if (value != null) value.IsSelected = true; 
      SetProperty(ref _selectedItem, value); 
     } 
    } 
} 

public class Item : BindableBase 
{ 
    private bool _isSelected; 

    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set { SetProperty(ref _isSelected, value); } 
    } 
} 

Другим решением было бы редактировать ListBoxItem.ControlTemplate вместо ListBox.ItemTemplate, где вы можете DataBind видимость ListBoxItem.IsSelected свойство, использовать визуальные состояния.

1

Вот что вы хотите сделать. Вы хотите использовать свойство ListViewItem.IsSelected, которое изначально задано ListView. Затем вы хотите отреагировать на это изменение стоимости и установить визуальное состояние, которое отображает или скрывает ваши данные.

Как это:

class MyModel 
{ 
    public bool IsSelected { get; set; } 
} 

class MyList : Windows.UI.Xaml.Controls.ListView 
{ 
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item) 
    { 
     var model = item as MyModel; 
     var listViewItem = element as Windows.UI.Xaml.Controls.ListViewItem; 

     var binding = new Windows.UI.Xaml.Data.Binding 
     { 
      Source = model, 
      Mode = Windows.UI.Xaml.Data.BindingMode.TwoWay, 
      Path = new PropertyPath(nameof(model.IsSelected)), 
     }; 
     listViewItem.SetBinding(Windows.UI.Xaml.Controls.ListViewItem.IsSelectedProperty, binding); 
     base.PrepareContainerForItemOverride(element, item); 
    } 
} 

достаточно смешной, но этот код несколько основан на коде, используемую для переменных размеров сеток обертывания. Здесь вы можете прочитать оригинальную статью.

http://blog.jerrynixon.com/2012/08/windows-8-beauty-tip-using.html

Если вы хотите узнать больше о визуальных Штатах, вы можете прочитать более статью в блоге я писал на ту же тему.

http://blog.jerrynixon.com/2013/11/windows-81-how-to-use-visual-states-in.html

Что-то вроде этого:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> 

    <Interactivity:Interaction.Behaviors> 
     <Core:DataTriggerBehavior Binding="{Binding IsSelected}" Value="True"> 
      <Core:GoToStateAction StateName="BigVisualState"/> 
     </Core:DataTriggerBehavior> 
     <Core:DataTriggerBehavior Binding="{Binding IsSelected}" Value="False"> 
      <Core:GoToStateAction StateName="LittleVisualState"/> 
     </Core:DataTriggerBehavior> 
    </Interactivity:Interaction.Behaviors> 

    <VisualStateManager.VisualStateGroups> 
     <VisualStateGroup x:Name="VisualStateGroup"> 
      <VisualState x:Name="BigVisualState"/> 
      <VisualState x:Name="LittleVisualState"/> 
     </VisualStateGroup> 
    </VisualStateManager.VisualStateGroups> 

</Grid> 

Если вы хотели бы узнать больше о XAML поведения в приложениях для Windows, вы можете прочитать статью я написал на эту тему.

http://blog.jerrynixon.com/2013/10/everything-i-know-about-behaviors-in.html

Я также записал курс вам хотелось бы.

https://mva.microsoft.com/en-US/training-courses/designing-your-xaml-ui-with-blend-jump-start-8260?l=p2dPykKy_5104984382

Я надеюсь, что это помогает.

Удачи!

Смежные вопросы