MAUI Bug:使用 ListView.GroupHeaderTemplate 后,ListView 内容消失。

huangapple go评论72阅读模式
英文:

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:

&lt;toolkit:Expander Margin=&quot;0,0,0,30&quot;&gt;
    &lt;toolkit:Expander.Header&gt;
        &lt;Label Text=&quot;Tops&quot; Style=&quot;{StaticResource labelExpander}&quot;  /&gt;
    &lt;/toolkit:Expander.Header&gt;
    &lt;Border Stroke=&quot;#888&quot;
            StrokeThickness=&quot;2&quot;
            StrokeShape=&quot;RoundRectangle 10&quot;
            HorizontalOptions=&quot;Fill&quot;&gt;
        &lt;VerticalStackLayout Margin=&quot;16&quot;&gt;
            &lt;Label&gt;Test&lt;/Label&gt;
            &lt;ListView ItemsSource=&quot;{Binding TopGroups}&quot; IsGroupingEnabled=&quot;True&quot;&gt;
                &lt;ListView.GroupHeaderTemplate&gt;
                    &lt;DataTemplate&gt;
                        &lt;ViewCell&gt;
                            &lt;Label Text=&quot;{Binding Name}&quot;
                                   FontSize=&quot;18&quot;
                                   FontAttributes=&quot;Bold&quot; /&gt;
                        &lt;/ViewCell&gt;
                    &lt;/DataTemplate&gt;
                &lt;/ListView.GroupHeaderTemplate&gt;
                &lt;ListView.ItemTemplate&gt;
                    &lt;DataTemplate&gt;
                        &lt;ViewCell&gt;
                            &lt;Grid Padding=&quot;10&quot; &gt;
                                &lt;Grid.RowDefinitions&gt;
                                    &lt;RowDefinition Height=&quot;Auto&quot; /&gt;
                                &lt;/Grid.RowDefinitions&gt;
                                &lt;Grid.ColumnDefinitions&gt;
                                    &lt;ColumnDefinition Width=&quot;Auto&quot; /&gt;
                                    &lt;ColumnDefinition Width=&quot;10&quot; /&gt;
                                    &lt;ColumnDefinition Width=&quot;Auto&quot; /&gt;
                                &lt;/Grid.ColumnDefinitions&gt;
                                &lt;Label Grid.Column=&quot;0&quot;    
                                       Text=&quot;{Binding Numbering}&quot;/&gt;
                                &lt;Label Grid.Column=&quot;2&quot;
                                       Text=&quot;{Binding ToText1}&quot;/&gt;
                            &lt;/Grid&gt;
                        &lt;/ViewCell&gt;
                    &lt;/DataTemplate&gt;
                &lt;/ListView.ItemTemplate&gt;
            &lt;/ListView&gt;
        &lt;/VerticalStackLayout&gt;
    &lt;/Border&gt;
&lt;/toolkit:Expander&gt;

MyPage.xaml.cs:

public partial class SitzungsPage
{
    public MyPage(MyPageViewModel myPageViewModel)
    {
        BindingContext = myPageViewModel;
        InitializeComponent();
    }
    //...
}

MyPageViewModel.cs(相关摘录,使用CommunityToolkit.Maui):

[ObservableProperty]
private List&lt;TopGroup&gt; _topGroups;

private void CreateTopGroups()
{
    TopGroups = new List&lt;TopGroup&gt;();
    var tops = new List&lt;Top&gt;();

    foreach (var to in ToDtos)
    {
        var top = new Top();

        switch (to.Status)
        {
            case 1:
            {
                _isPuplicList ??= true;
                if (_isPuplicList is false)
                {
                    TopGroups.Add(new TopGroup(&quot;Not Public&quot;, tops));
                    tops = new List&lt;Top&gt;();
                    _isPuplicList = true;
                }
                break;
            }
            case 2:
            {
                _isPuplicList ??= false;
                if (_isPuplicList is true)
                {
                    TopGroups.Add(new TopGroup(&quot;Public&quot;, tops));
                    tops = new List&lt;Top&gt;();
                    _isPuplicList = false;
                }
                break;
            }
        }

        top.ToText1 = to.ToText1;
        top.Numbering = to.Number;
        tops.Add(top);
    }

    if (tops.Count &gt; 0 &amp;&amp; _isPuplicList is not null)
    {
        TopGroups.Add(new TopGroup((bool)_isPuplicList ? &quot;Public&quot; : &quot;Not Public&quot;, tops));
    }
}

TopGroup:

public class TopGroup : List&lt;Top&gt;
{
    public string Name { get; private set; }

    public TopGroup(string name, IEnumerable&lt;Top&gt; tops) : base(tops)
    {
        Name = name;
    }
}

Top:

public class Top
{
    public string Numbering { get; set; }

    public string ToText1 { get; set; }

    public List&lt;DokumentDto&gt; 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:

&lt;toolkit:Expander Margin=&quot;0,0,0,30&quot;&gt;
    &lt;toolkit:Expander.Header&gt;
        &lt;Label Text=&quot;Tops&quot; Style=&quot;{StaticResource labelExpander}&quot;  /&gt;
    &lt;/toolkit:Expander.Header&gt;
    &lt;Border Stroke=&quot;#888&quot;
            StrokeThickness=&quot;2&quot;
            StrokeShape=&quot;RoundRectangle 10&quot;
            HorizontalOptions=&quot;Fill&quot;&gt;
        &lt;VerticalStackLayout Margin=&quot;16&quot;&gt;
            &lt;Label&gt;Test&lt;/Label&gt;
            &lt;ListView ItemsSource=&quot;{Binding TopGroups}&quot; IsGroupingEnabled=&quot;True&quot;&gt;
                &lt;ListView.GroupHeaderTemplate&gt;
                    &lt;DataTemplate&gt;
                        &lt;ViewCell&gt;
                            &lt;Label Text=&quot;{Binding Name}&quot;
                                   FontSize=&quot;18&quot;
                                   FontAttributes=&quot;Bold&quot; /&gt;
                        &lt;/ViewCell&gt;
                    &lt;/DataTemplate&gt;
                &lt;/ListView.GroupHeaderTemplate&gt;
                &lt;ListView.ItemTemplate&gt;
                    &lt;DataTemplate&gt;
                        &lt;ViewCell&gt;
                            &lt;Grid Padding=&quot;10&quot; &gt;
                                &lt;Grid.RowDefinitions&gt;
                                    &lt;RowDefinition Height=&quot;Auto&quot; /&gt;
                                &lt;/Grid.RowDefinitions&gt;
                                &lt;Grid.ColumnDefinitions&gt;
                                    &lt;ColumnDefinition Width=&quot;Auto&quot; /&gt;
                                    &lt;ColumnDefinition Width=&quot;10&quot; /&gt;
                                    &lt;ColumnDefinition Width=&quot;Auto&quot; /&gt;
                                &lt;/Grid.ColumnDefinitions&gt;
                                &lt;Label Grid.Column=&quot;0&quot;    
                                       Text=&quot;{Binding Numbering}&quot;/&gt;
                                &lt;Label Grid.Column=&quot;2&quot;
                                       Text=&quot;{Binding ToText1}&quot;/&gt;
                            &lt;/Grid&gt;
                        &lt;/ViewCell&gt;
                    &lt;/DataTemplate&gt;
                &lt;/ListView.ItemTemplate&gt;
            &lt;/ListView&gt;
        &lt;/VerticalStackLayout&gt;
    &lt;/Border&gt;
&lt;/toolkit:Expander&gt;

MyPage.xaml.cs:

public partial class SitzungsPage
{
    public MyPage(MyPageViewModel myPageViewModel)
    {
        BindingContext = myPageViewModel;
        InitializeComponent();
    }
    //...
}

MyPageViewModel.cs (relevant excerpts, using CommunityToolkit.Maui):

[ObservableProperty]
private List&lt;TopGroup&gt; _topGroups;

private void CreateTopGroups()
{
    TopGroups = new List&lt;TopGroup&gt;();
    var tops = new List&lt;Top&gt;();

    foreach (var to in ToDtos)
    {
        var top = new Top();

        switch (to.Status)
        {
            case 1:
            {
                _isPuplicList ??= true;
                if (_isPuplicList is false)
                {
                    TopGroups.Add(new TopGroup(&quot;Not Public&quot;, tops));
                    tops = new List&lt;Top&gt;();
                    _isPuplicList = true;
                }
                break;
            }
            case 2:
            {
                _isPuplicList ??= false;
                if (_isPuplicList is true)
                {
                    TopGroups.Add(new TopGroup(&quot;Public&quot;, tops));
                    tops = new List&lt;Top&gt;();
                    _isPuplicList = false;
                }
                break;
            }
        }

        top.ToText1 = to.ToText1;
        top.Numbering = to.Number;
        tops.Add(top);
    }

    if (tops.Count &gt; 0 &amp;&amp; _isPuplicList is not null)
    {
        TopGroups.Add(new TopGroup((bool)_isPuplicList ? &quot;Public&quot; : &quot;Not Public&quot;, tops));
    }
}

TopGroup:

public class TopGroup : List&lt;Top&gt;
{
    public string Name { get; private set; }

    public TopGroup(string name, IEnumerable&lt;Top&gt; tops) : base(tops)
    {
        Name = name;
    }
}

Top:

public class Top
{
    public string Numbering { get; set; }

    public string ToText1 { get; set; }

    public List&lt;DokumentDto&gt; 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&lt;TopGroup&gt;();

...
   topGroups.Add(...);   &lt;-- 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&lt;TopGroup&gt; _topGroups;

更改为:

public ObservableCollection&lt;TopGroup&gt; TopGroups { get; private set; } = new();

以及:

TopGroups = new List&lt;TopGroup&gt;();

更改为:

TopGroups.Clear();

问题在于当TopGroups被设置为new()时,会触发更改事件,因此它是空的。

英文:

I have been able to solve the problem by changing the ObservableProperty to ObservableCollection in ViewModel:

[ObservableProperty]
private List&lt;TopGroup&gt; _topGroups;

to

public ObservableCollection&lt;TopGroup&gt; TopGroups { get; private set; } = new();

and

TopGroups = new List&lt;TopGroup&gt;();

to

TopGroups.Clear();

The problem was that the change event was triggered when TopGroups was set to new(). So it was empty.

huangapple
  • 本文由 发表于 2023年6月1日 18:07:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/76380811.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定