【发布时间】:2019-06-10 22:54:27
【问题描述】:
在ListView 中显示组标题,而不是按排序键。
您好,我正在为 Windows 10 移动版开发 UWP 应用程序。
我有一个ListView,其中包含来自 SQLite 数据库的项目。每个项目都属于一个类别,ListView 按类别分组。在显示中,组的标题是类别的名称,这些类别按字母顺序排序。
XAML 代码的主要元素是:
<ListView x:Name="listBoxobj"
ItemsSource="{Binding Source={StaticResource cvsource}}"
BorderBrush="#FF141EE4"
Margin="0,0,0,0"
HorizontalAlignment="Stretch"
SelectionMode="None"
IsItemClickEnabled="True"
RightTapped="listBoxobj_RightTapped"
SelectedItem="{Binding Name}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="NameTxt" Grid.Column="0" Margin="0,0,0,0" TextWrapping="Wrap" Text="{Binding NomArt}" FontSize="20" Foreground="White"/>
<TextBlock x:Name="QteArtTxt" Grid.Column="0" Margin="20,0,0,0" TextWrapping="Wrap" Text="{Binding QuantArt}" FontSize="20" Foreground="DarkGray" FontStyle="Italic"/>
<TextBlock x:Name="UniteMesureTxt" Grid.Column="0" Margin="10,0,0,0" TextWrapping="Wrap" Text="{Binding UnitArt}" FontSize="20" Foreground="DarkGray" FontStyle="Italic"/>
</StackPanel>
<Button x:Name="btnPanier" Grid.Column="1" Height="35" Width="35" Tag="{Binding}" Click="btnPanier_Click">
<Button.Background>
<ImageBrush ImageSource="/Assets/Images/icone_caddie_40x40.png" Stretch="UniformToFill">
</ImageBrush>
</Button.Background>
</Button>
<TextBlock x:Name="NoteTxt" Grid.Row="2" Margin="0,20,0,0" TextWrapping="Wrap" Text="{Binding NoteArt}" FontSize="16" Foreground="DarkGray" FontStyle="Italic"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}" Foreground="CadetBlue" FontSize="18" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<MenuFlyout x:Name="MenuFlyoutContext" x:Key="FlyoutBaseKey">
<MenuFlyoutItem x:Name="MFSubMenu1" x:Uid="MenuFlyoutModif" Click="MFSubMenu1_Click"/>
<MenuFlyoutItem x:Name="MFSubMenu2" x:Uid="MenuFlyoutDelete" Click="MFSubMenu2_Click"/>
</MenuFlyout>
</ListView.Resources>
<FlyoutBase.AttachedFlyout>
<StaticResource ResourceKey="FlyoutBaseKey"/>
</FlyoutBase.AttachedFlyout>
</ListView>
下面是显示 ListView 的代码:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
currentListeAchat = e.Parameter as string;
textBlock.Text = resourceLoader.GetString("PanierTitre") + " " + currentListeAchat;
//
Achats = new ObservableCollection<Achat>();
AchatsIn = new ObservableCollection<Achat>();
//
DB_PanierList = dbpaniers.GetAllPaniers();
var query = DB_PanierList.Where(x => x.NomListe == currentListeAchat & x.InOut == "Out");
//
foreach (var item in query)
{
string nomart = item.Name;
string quantart = item.QteArt;
string noteart = item.Note;
string catart = item.NomCat;
int catorder = item.OrdreCat;
string unitart = item.UniteMesure;
string inout = item.InOut;
Achats.Add(new Achat()
{
NomArt = nomart,
QuantArt = quantart,
NoteArt = noteart,
CatArt = catart,
CatOrder = catorder,
UnitArt = unitart,
InOut = inout
});
}
//
_groupingCollection = new ObservableGroupingCollection<string, Achat>(Achats);
_groupingCollection.ArrangeItems(new CatSorter(), (x => x.CatOrder.ToString()));
GroupedAchats = _groupingCollection.Items;
cvsource.Source = GroupedAchats;
//
//
var queryin = DB_PanierList.Where(x => x.NomListe == currentListeAchat & x.InOut == "In");
//
foreach (var item in queryin)
{
string nomart = item.Name;
string quantart = item.QteArt;
string noteart = item.Note;
string catart = item.NomCat;
int catorder = item.OrdreCat;
string unitart = item.UniteMesure;
string inout = item.InOut;
AchatsIn.Add(new Achat()
{
NomArt = nomart,
QuantArt = quantart,
NoteArt = noteart,
CatArt = catart,
CatOrder = catorder,
UnitArt = unitart,
InOut = inout
});
}
//
_groupingCollectionIn = new ObservableGroupingCollection<string, Achat>(AchatsIn);
_groupingCollectionIn.ArrangeItems(new CatSorter(), (x => x.CatArt));
GroupedAchatsIn = _groupingCollectionIn.Items;
cvsourceIn.Source = GroupedAchatsIn;
//
// Register for hardware and software back request from the system
SystemNavigationManager systemNavigationManager = SystemNavigationManager.GetForCurrentView();
systemNavigationManager.BackRequested += OnBackRequested;
}
还有 ObservableGroupingCollection 类:
public class ObservableGroupingCollection<K, T> where K : IComparable
{
public ObservableGroupingCollection(ObservableCollection<T> collection)
{
_rootCollection = collection;
_rootCollection.CollectionChanged += _rootCollection_CollectionChanged;
}
ObservableCollection<T> _rootCollection;
private void _rootCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
HandleCollectionChanged(e);
}
ObservableCollection<Grouping<K, T>> _items;
public ObservableCollection<Grouping<K, T>> Items
{
get { return _items; }
}
IComparer<T> _sortOrder;
Func<T, K> _groupFunction;
public void ArrangeItems(IComparer<T> sortorder, Func<T, K> group)
{
_sortOrder = sortorder;
_groupFunction = group;
var temp = _rootCollection
.OrderBy(i => i, _sortOrder)
.GroupBy(_groupFunction)
.ToList()
.Select(g => new Grouping<K, T>(g.Key, g));
_items = new ObservableCollection<Grouping<K, T>>(temp);
}
private void HandleCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
var item = (T)(e.NewItems[0]);
var value = _groupFunction.Invoke(item);
// find matching group if exists
var existingGroup = _items.FirstOrDefault(g => g.Key.Equals(value));
if (existingGroup == null)
{
var newlist = new List<T>();
newlist.Add(item);
// find first group where Key is greater than this key
var insertBefore = _items.FirstOrDefault(g => ((g.Key).CompareTo(value)) > 0);
if (insertBefore == null)
{
// not found - add new group to end of list
_items.Add(new Grouping<K, T>(value, newlist));
}
else
{
// insert new group at this index
_items.Insert(_items.IndexOf(insertBefore), new Grouping<K, T>(value, newlist));
}
}
else
{
// find index to insert new item in existing group
int index = existingGroup.ToList().BinarySearch(item, _sortOrder);
if (index < 0)
{
existingGroup.Insert(~index, item);
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Remove)
{
var item = (T)(e.OldItems[0]);
var value = _groupFunction.Invoke(item);
var existingGroup = _items.FirstOrDefault(g => g.Key.Equals(value));
if (existingGroup != null)
{
// find existing item and remove
var targetIndex = existingGroup.IndexOf(item);
existingGroup.RemoveAt(targetIndex);
// remove group if zero items
if (existingGroup.Count == 0)
{
_items.Remove(existingGroup);
}
}
}
}
}
可以看出,header 是由以下行经典生成的:
<TextBlock Text="{Binding Key}" Foreground="CadetBlue" FontSize="18" />
我希望用户能够根据自己的选择对类别进行排序。所以我添加了一个OrderCat (int) 字段,它将类别从 1 编号到(类别数)。在我后面的代码中,我将ListView 分组不是在Category 字段上,而是在OrderCat 上,并且效果很好(这些组按所选顺序显示,而不是按字母顺序)。唯一的问题是因为{Binding Key},标题显示数字(OdreCat),而不是类别名称。如何显示数字对应的名称?
有人可以帮我吗?
【问题讨论】:
-
我无法在您的代码中获取 OrderCat。你能分享可以重现问题的迷你样本吗?
-
看看语义缩放组件,我相信它对您的解决方案非常有帮助。基本上您需要配置放大和缩小显示,对于缩小您可以只显示类别,对于放大您可以显示分组列表。 docs.microsoft.com/pt-br/windows/uwp/design/…
-
你好 Nico,很抱歉缺少代码,但新的网站编辑规则不允许我发布它。我会再试一次,包括后面的代码。
-
对于 Ghuilherme:语义缩放不适用于我的情况,因为当用户删除列表中的项目时,我必须刷新所有列表以反映修改。