2016-02-02 41 views
5

Esistono soluzioni a questo problema per i framework UI basati su XAML precedenti (WPF/SL) ma non sono facilmente adattabili alla piattaforma Windows universale.Crea un ListBox con elementi che si espandono quando selezionato (Fisarmonica)

Sto cercando di creare un elenco di elementi che mostrano solo dettagli limitati nello stato predefinito e si espande, quando è selezionato, per modificare rapidamente alcuni dati.
Non ho trovato un modo per creare un comportamento di espansione, sebbene sia simile a ciò che fa l'applicazione Mail di Windows 10, con le conversazioni. Quando viene selezionato un messaggio di una conversazione, gli altri messaggi di quel tipo di conversazione scendono verso il basso o verso il basso.

Di seguito è riportato un esempio di un elenco in cui mi piacerebbe visualizzare solo il nome all'inizio.

<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> 

In WPF, tale comportamento potrebbe essere raggiunto con i trigger Style.Triggers ma non sono più disponibili.

codice sorgente originale su GitHub

+0

Hai ancora trigger disponibili in UWP e ci sono molti modi per farlo in puro XAML, un modo semplice e veloce che potrei pensare di fare. Crea un ItemTemplate con un ToggleButton stilizzato e un pannello sotto di esso collassato. Quindi associare la visibilità del pannello allo stato IsChecked di ToggleButton e aggiungere un convertitore Bool to Visibility, voilà, fatto. –

risposta

0

ho creato un espandibile controllo ListView per UWP - si può trovare here nel repository GitHub. In realtà è una versione con porting dello WPF Expander che ho adattato per funzionare con la piattaforma Windows universale.

È possibile trovare la mia domanda e rispondere qui su StackOverflow.

0

Come Chris Said, è possibile aggiungere una proprietà in ViewModel per controllare il comportamento di espansione, ma è necessario modificare ViewModel. Se non vuoi farlo, ecco un altro approccio:

In primo luogo, abbiamo bisogno di due DataTemplate, uno per la visualizzazione di brevi informazioni e l'altro per la visualizzazione dei dettagli. Per esempio:

<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> 

Poi nel ListBox impostare il valore predefinito ItemTemplate a brevi modello informativo.

<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> 

Infine, aggiungere un gestore di eventi per SelectionChanged evento e in questo cambiamento gestore ContentTemplate per l'elemento selezionato e non selezionato.

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

Qui è una soluzione utilizzando 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); } 
    } 
} 

Un'altra soluzione potrebbe essere quella di modificare ListBoxItem.ControlTemplate invece di ListBox.ItemTemplate, in cui è possibile DataBind visibilità ListBoxItem.IsSelected proprietà, sfruttare gli stati visivi.

1

Ecco cosa vuoi fare. Si desidera utilizzare la proprietà ListViewItem.IsSelected impostata in modo nativo da ListView. Quindi, vuoi reagire a quel cambiamento di valore e impostare uno stato visivo che rivela o nasconde i tuoi dettagli.

Ti piace questa:

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); 
    } 
} 

Abbastanza divertente ma questo codice è un po 'basato sul codice utilizzato per le griglie avvolgere di dimensioni variabili. Puoi leggere l'articolo originale qui.

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

Se volete saperne di più sugli stati visivi, si potrebbe leggere il blog articolo che ho scritto sullo stesso argomento.

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

Qualcosa di simile a questo:

<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> 

Se volete saperne di più su comportamenti XAML in applicazioni Windows, è possibile leggere l'articolo che ho scritto su questo argomento.

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

Ho anche registrato un corso ti avrebbe fatto piacere.

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

Spero che questo aiuta.

Buona fortuna!