英文:
MAUI Bug ListView content disappeared by using ListView.GroupHeaderTemplate
问题
I'm using a ListView with Binding Group and IsGroupingEnabled="True" for headers and I don't get any content displayed.
现在,当我注释掉xaml部分中的<ListView.GroupHeaderTemplate>或取消注释之前注释的<ListView.GroupHeaderTemplate>部分后(在Windows上启动应用程序后),内容会显示出来。
当我使用普通的List而不是*(Top-)Group和没有IsGroupingEnabled时,它正常工作。
Label的宽度内容Test*总是显示。
当我将ListView更改为CollectionView时,我得到相同的结果。普通列表显示出来,但分组列表没有显示。
为什么在调用页面时不立即显示内容,只有在注释代码(在xaml中)之后才显示?
XAML:
<toolkit:Expander Margin="0,0,0,30">
<toolkit:Expander.Header>
<Label Text="Tops" Style="{StaticResource labelExpander}" />
</toolkit:Expander.Header>
<Border Stroke="#888"
StrokeThickness="2"
StrokeShape="RoundRectangle 10"
HorizontalOptions="Fill">
<VerticalStackLayout Margin="16">
<Label>Test</Label>
<ListView ItemsSource="{Binding TopGroups}" IsGroupingEnabled="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"
FontSize="18"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding Numbering}"/>
<Label Grid.Column="2"
Text="{Binding ToText1}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</VerticalStackLayout>
</Border>
</toolkit:Expander>
MyPage.xaml.cs:
public partial class SitzungsPage
{
public MyPage(MyPageViewModel myPageViewModel)
{
BindingContext = myPageViewModel;
InitializeComponent();
}
//...
}
MyPageViewModel.cs(相关摘录,使用CommunityToolkit.Maui):
[ObservableProperty]
private List<TopGroup> _topGroups;
private void CreateTopGroups()
{
TopGroups = new List<TopGroup>();
var tops = new List<Top>();
foreach (var to in ToDtos)
{
var top = new Top();
switch (to.Status)
{
case 1:
{
_isPuplicList ??= true;
if (_isPuplicList is false)
{
TopGroups.Add(new TopGroup("Not Public", tops));
tops = new List<Top>();
_isPuplicList = true;
}
break;
}
case 2:
{
_isPuplicList ??= false;
if (_isPuplicList is true)
{
TopGroups.Add(new TopGroup("Public", tops));
tops = new List<Top>();
_isPuplicList = false;
}
break;
}
}
top.ToText1 = to.ToText1;
top.Numbering = to.Number;
tops.Add(top);
}
if (tops.Count > 0 && _isPuplicList is not null)
{
TopGroups.Add(new TopGroup((bool)_isPuplicList ? "Public" : "Not Public", tops));
}
}
TopGroup:
public class TopGroup : List<Top>
{
public string Name { get; private set; }
public TopGroup(string name, IEnumerable<Top> tops) : base(tops)
{
Name = name;
}
}
Top:
public class Top
{
public string Numbering { get; set; }
public string ToText1 { get; set; }
public List<DokumentDto> Documents { get; set; }
}
英文:
I'm using a ListView with Binding Group and IsGroupingEnabled="True " for headers and I don't get any content displayed.
Now when I comment out the xaml section of <ListView.GroupHeaderTemplate> or comment in the previously commented out section of <ListView.GroupHeaderTemplate> after launching the app (on Windows), the content is displayed.
When I use a common List instead of the (Top-)Group and no IsGroupingEnabled it works fine.
The Label width content Test is always shown.
When I changed ListView to CollectionView I get the same result. The plain List is shown, but not a grouped list.
Why is the content not shown immediately when the page is called, only after commenting in the code (in xaml)?
XAML:
<toolkit:Expander Margin="0,0,0,30">
<toolkit:Expander.Header>
<Label Text="Tops" Style="{StaticResource labelExpander}" />
</toolkit:Expander.Header>
<Border Stroke="#888"
StrokeThickness="2"
StrokeShape="RoundRectangle 10"
HorizontalOptions="Fill">
<VerticalStackLayout Margin="16">
<Label>Test</Label>
<ListView ItemsSource="{Binding TopGroups}" IsGroupingEnabled="True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Name}"
FontSize="18"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="10" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0"
Text="{Binding Numbering}"/>
<Label Grid.Column="2"
Text="{Binding ToText1}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</VerticalStackLayout>
</Border>
</toolkit:Expander>
MyPage.xaml.cs:
public partial class SitzungsPage
{
public MyPage(MyPageViewModel myPageViewModel)
{
BindingContext = myPageViewModel;
InitializeComponent();
}
//...
}
MyPageViewModel.cs (relevant excerpts, using CommunityToolkit.Maui):
[ObservableProperty]
private List<TopGroup> _topGroups;
private void CreateTopGroups()
{
TopGroups = new List<TopGroup>();
var tops = new List<Top>();
foreach (var to in ToDtos)
{
var top = new Top();
switch (to.Status)
{
case 1:
{
_isPuplicList ??= true;
if (_isPuplicList is false)
{
TopGroups.Add(new TopGroup("Not Public", tops));
tops = new List<Top>();
_isPuplicList = true;
}
break;
}
case 2:
{
_isPuplicList ??= false;
if (_isPuplicList is true)
{
TopGroups.Add(new TopGroup("Public", tops));
tops = new List<Top>();
_isPuplicList = false;
}
break;
}
}
top.ToText1 = to.ToText1;
top.Numbering = to.Number;
tops.Add(top);
}
if (tops.Count > 0 && _isPuplicList is not null)
{
TopGroups.Add(new TopGroup((bool)_isPuplicList ? "Public" : "Not Public", tops));
}
}
TopGroup:
public class TopGroup : List<Top>
{
public string Name { get; private set; }
public TopGroup(string name, IEnumerable<Top> tops) : base(tops)
{
Name = name;
}
}
Top:
public class Top
{
public string Numbering { get; set; }
public string ToText1 { get; set; }
public List<DokumentDto> Documents { get; set; }
}
答案1
得分: 1
现在问题已经编辑,显示了如何填充TopGroup
,问题更容易被发现。
一个高效的解决方案是在列表填充后再设置属性。在本地变量中创建列表;在填充本地列表后设置属性:
var topGroups = new List<TopGroup>();
...
topGroups.Add(...); // 每次添加项目时都执行这个操作。
...
TopGroups = topGroups; // 最后设置属性。
当从头开始创建列表时,这可能比清除属性的列表并逐个添加它们的性能要好,这可能会导致多次更新事件。或者差异可能是可以忽略的,这取决于何时调用它,列表中有多少项目,每个项目的显示复杂性。
英文:
Now that question has been edited to show how TopGroup
is filled, the problem is easier to spot.
An efficient solution is to not set the property until the list is filled. Create the list in a local variable; set property after filling the local list:
var topGroups = new List<TopGroup>();
...
topGroups.Add(...); <-- everywhere that an item is added.
...
TopGroups = topGroups; // Finally, set the property.
When a list is being created from scratch, this might be better performance than clearing the property's list, and adding them one at a time, which could result in multiple update events. Or the difference might be negligible, depending on when this is called, how many items in list, complexity of display of each item.
答案2
得分: 0
我已成功通过在ViewModel中将ObservableProperty更改为ObservableCollection来解决了该问题:
[ObservableProperty]
private List<TopGroup> _topGroups;
更改为:
public ObservableCollection<TopGroup> TopGroups { get; private set; } = new();
以及:
TopGroups = new List<TopGroup>();
更改为:
TopGroups.Clear();
问题在于当TopGroups被设置为new()时,会触发更改事件,因此它是空的。
英文:
I have been able to solve the problem by changing the ObservableProperty to ObservableCollection in ViewModel:
[ObservableProperty]
private List<TopGroup> _topGroups;
to
public ObservableCollection<TopGroup> TopGroups { get; private set; } = new();
and
TopGroups = new List<TopGroup>();
to
TopGroups.Clear();
The problem was that the change event was triggered when TopGroups was set to new(). So it was empty.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论