创建一个列表框,其中包含在选定时展开的项目(折叠项)
本文关键字:定时 项目 折叠 一个 列表 创建 包含 | 更新日期: 2023-09-27 18:32:52
较旧的基于XAML的UI框架(WPF/SL(,这个问题有解决方案,但它们不容易适应通用Windows平台。
我正在尝试创建一个项目列表,这些项目列表在默认状态下仅显示有限的详细信息,并在选择时展开以快速编辑某些数据。
我还没有找到一种方法来创建这种扩展行为,尽管它类似于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 上的原始源代码
这是你想要做的。您希望使用由 ListView 本机设置的 ListViewItem.IsSelected 属性。然后,您希望对该值更改做出反应,并设置显示或隐藏详细信息的视觉状态。
喜欢这个:
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>
如果你想了解有关 Windows 应用中 XAML 行为的详细信息,可以阅读我写的有关该主题的文章。
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
我希望这有所帮助。
祝你好运!
我为 UWP 创建了一个可扩展的ListView
控件 - 你可以在 GitHub 存储库中找到它。它实际上是WPF Expander
的移植版本,我将其改编为与通用Windows平台一起使用。
你可以在StackOverflow上找到我的问题和答案。
像 Chris Said 一样,我们可以在 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"];
}
下面是一个使用 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,您可以在其中将数据可见性绑定到 ListBoxItem.IsSelected 属性,从而利用视觉状态。