2016-02-02 12 views
5

Có các giải pháp cho vấn đề này đối với các giao diện người dùng dựa trên XAML cũ hơn (WPF/SL) nhưng chúng không dễ dàng thích nghi với nền tảng Windows phổ biến.Tạo một ListBox với các mục mở rộng khi được chọn (Accordion)

Tôi đang cố gắng tạo danh sách các mục chỉ hiển thị chi tiết bị giới hạn ở trạng thái mặc định và mở rộng, khi được chọn, để chỉnh sửa nhanh một số dữ liệu.
Tôi đã không tìm thấy cách để tạo ra một hành vi mở rộng, mặc dù nó tương tự như ứng dụng Windows 10 Mail, với các cuộc trò chuyện. Khi một tin nhắn của một cuộc hội thoại được chọn, các tin nhắn khác của loại cuộc trò chuyện đó sẽ bị rơi xuống hoặc trượt xuống.

Dưới đây là ví dụ về danh sách nơi tôi chỉ muốn hiển thị tên lúc đầu.

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

Trong WPF, hành vi này có thể đạt được với trình kích hoạt Style.Triggers nhưng chúng không còn khả dụng nữa.

Original Source Code trên GitHub

+0

Bạn vẫn có các trình kích hoạt có sẵn cho bạn trong UWP và có một số cách bạn có thể thực hiện điều này trong XAML thuần túy, một cách nhanh chóng và đơn giản mà tôi có thể nghĩ đến khi thực hiện việc này. Tạo một ItemTemplate với một ToggleButton được tạo kiểu và một Panel bên dưới nó được cắt bớt. Sau đó, liên kết Hiển thị của bảng điều khiển với trạng thái IsChecked của ToggleButton và thêm một công cụ chuyển đổi Bool thành Visibility, thì đấy, xong. –

Trả lời

0

Tôi tạo ra một ListView kiểm soát có thể mở rộng cho UWP - bạn có thể tìm thấy nó here trong repo GitHub. Nó thực sự là một phiên bản chuyển của WPF Expander mà tôi thích nghi để làm việc với nền tảng cửa sổ phổ quát.

Bạn có thể tìm câu hỏi và câu trả lời của tôi tại đây trên StackOverflow.

0

Giống như Chris Said, chúng tôi có thể thêm thuộc tính trong ViewModel để kiểm soát hành vi mở rộng, nhưng điều này cần phải thay đổi ViewModel. Nếu bạn không muốn làm điều này, dưới đây là một cách tiếp cận khác:

Trước tiên, chúng tôi cần hai DataTemplate, một để hiển thị thông tin tóm tắt và một để hiển thị chi tiết. Ví dụ:

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

Sau đó, trong ListBox thiết lập mặc định ItemTemplate để tóm tắt mẫu thông tin.

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

Cuối cùng, thêm một xử lý sự kiện để SelectionChanged sự kiện và trong điều khiển biến đổi này ContentTemplate cho mục được chọn và không được chọn.

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

Dưới đây là một giải pháp sử dụng 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); } 
    } 
} 

Một giải pháp khác sẽ được chỉnh sửa ListBoxItem.ControlTemplate thay vì ListBox.ItemTemplate, nơi bạn có thể DataBind tầm nhìn đến ListBoxItem.IsSelected tài sản, tận dụng lợi thế của trạng thái trực quan.

1

Đây là những gì bạn muốn làm. Bạn muốn sử dụng thuộc tính ListViewItem.IsSelected vốn được đặt bởi ListView. Sau đó, bạn muốn phản ứng với thay đổi giá trị đó và đặt trạng thái trực quan cho biết hoặc ẩn chi tiết của bạn.

Như thế này:

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

Funny đủ nhưng mã này được phần nào dựa trên mã sử dụng cho lưới bọc kích thước khác nhau. Bạn có thể đọc bài viết gốc tại đây.

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

Nếu bạn muốn tìm hiểu thêm về Hoa Visual, bạn có thể đọc qua bài viết blog của tôi đã viết về cùng một chủ đề.

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

Something như thế này:

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

Nếu bạn muốn tìm hiểu thêm về hành vi XAML trong các ứng dụng Windows, bạn có thể đọc bài viết tôi đã viết về đề tài này.

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

tôi cũng ghi nhận một khóa học mà bạn thích.

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

Tôi hy vọng điều này sẽ giúp.

Chúc bạn may mắn!

Các vấn đề liên quan