点击新项目时折叠 Xamarin ListView 中的所有项目

Posted

技术标签:

【中文标题】点击新项目时折叠 Xamarin ListView 中的所有项目【英文标题】:Collapse all items in Xamarin ListView when a new item is tapped 【发布时间】:2021-07-09 23:50:58 【问题描述】:

我有一个看似相对简单的问题,但我想不通。

我有一个 Xamarin ListView,它使用 ViewCells 的项目模板,如下所示:

<ListView  HasUnevenRows="True"
           ItemsSource="Binding Devices" 
           ItemTemplate="StaticResource DeviceDataTemplateSelector"
           SelectionMode="None"
           ItemTapped="NewItemTapped"
           />

目前,“DeviceDataTemplateSelector”始终返回以下 ViewCell(稍后将添加更多 ViewCell)。

ViewCell 使用 Xamarin 社区工具包中的 Expander 控件

<ViewCell xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
        xmlns:ViewModel="clr-namespace:App.ViewModels"
        x:Class="App.UI.ViewCellStandardTemplate">

    <ViewCell.View>
        
        <!-- Calls an expander for each ViewCell. -->
        <xct:Expander HorizontalOptions="FillAndExpand"
                        VerticalOptions="FillAndExpand"
                        Margin="StaticResource UniversalMargin" 
                        >

            <xct:Expander.Header>
                <Grid HorizontalOptions="FillAndExpand" 
                        VerticalOptions="FillAndExpand"
                        Margin="StaticResource UniversalMargin">

                    <Grid.RowDefinitions>
                        <RowDefinition Height = "*" />
                    </Grid.RowDefinitions>

                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width = "*" />
                    </Grid.ColumnDefinitions>

                    <Label Grid.Row="0" Grid.Column="0" Text="Header Text" />

                </Grid>
            </xct:Expander.Header>

            <xct:Expander.Content>
                <Grid HorizontalOptions="FillAndExpand" 
                        VerticalOptions="FillAndExpand"
                        Margin="StaticResource UniversalMargin">

                    <Grid.RowDefinitions>
                        <RowDefinition Height = "*" />
                    </Grid.RowDefinitions>
                    
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width = "*" />
                    </Grid.ColumnDefinitions>

                    <Button Grid.Row="0"
                            Grid.Column="0" 
                            Text="Click Me" 
                            Command="Binding Source=RelativeSource AncestorType=x:Type ViewModel:PageViewModel, Mode=FindAncestorBindingContext, Path=ClickCommand"
                            CommandParameter="Binding ."
                            />

                </Grid>
            </xct:Expander.Content>

        </xct:Expander>

    </ViewCell.View>

</ViewCell>

到目前为止,所有这些都正常工作 - 问题是当我点击 ListView 中的一个项目时,我希望任何其他展开的项目都折叠起来。

换句话说,当我点击一个 ViewCell 来展开它时,我希望 ListView 中的所有其他 ViewCell 将它们各自的 Expander 控件的“IsExpanded”属性设置为 false。

我已尝试在 ListView 中调用“ItemTapped”事件,然后循环浏览 ListView 中的元素 - 我不确定这是否是正确的方法?

在 ViewCell 中访问 Expander 控件属性的最佳方式是什么?

我不知道该怎么做 - 任何帮助将不胜感激。

谢谢。

【问题讨论】:

当您“循环遍历 ListView 中的元素”时会发生什么?您是否成功地将“IsExpanded”属性设置为 false?但它实际上并没有折叠它们? 【参考方案1】:

更新

编辑提供纯UI解决方案,灵感来自get cells from ListView(或者可以试试这个highlight the selected item)

两步:

    在 XAML 中定义 ViewCellListView
<ListView x:Name="MyList" ...>
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <xct:Expander Tapped="Expander_Tapped" ...>
    在 XAML.cs 中定义方法:
        private void Expander_Tapped(object sender, EventArgs e)
        
            var expander = sender as Expander;
            var state = expander.IsExpanded;

            var cells = MyList.GetType().GetRuntimeProperties()
                .FirstOrDefault(info => info.Name == "TemplatedItems")?.GetValue(MyList);
            if (cells != null)  
                foreach (ViewCell cell in cells as ITemplatedItemsList<Cell>)
                
                    if (cell.BindingContext != null)
                    
                        var child = cell.View as Expander;
                        child.IsExpanded = false;
                    
                
            

            expander.IsExpanded = state;
        

上一个答案:

与其操作视图属性,我更愿意在模型类中进行操作。

这里的三个步骤:

    在模型类中添加布尔属性。
 public class YourDeviceModel : INotifyPropertyChanged
    
        private bool flag;

        public bool Flag
        
            get => flag;
            set
            
                flag = value;
                OnPropertyChanged("Flag");
            
        

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string name)
        
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        
    
    单击时在 ViewModel 中定义 TapCommand(如果使用 MVVM)
    public ICommand TapCommand => new Command<YourDeviceModel>(OnItemTapped);

    private void OnItemTapped(YourDeviceModel currentSelection)
    
        //if your Devices is a ObservableCollection, convert it and reset all flags
        Devices.ToList().ForEach(x => x.Flag = false);
        //set the current one to true
        currentSelection.Flag = true;
    
    Expander 中添加属性和命令绑定(在ListView 中删除ItemTapped
    <xct:Expander
        IsExpanded="Binding Flag, Mode=TwoWay"
        Command="Binding Source=RelativeSource AncestorType=x:Type ViewModel:PageViewModel, Mode=FindAncestorBindingContext, Path=TapCommand"
        CommandParameter="Binding .">

【讨论】:

这可能不是一个好主意。 IsExpanded 在 Model 域中可能没有任何意义;它可能纯粹是视图状态的一部分。 (仅供参考:这是数据绑定更大问题的一部分;它擅长从模型进行简单映射,但一旦视图需求更复杂,就不是很好了。所以任何一个都做你做的事情,这与分离视图的目标背道而驰来自模型,或者需要每个项目的“视图模型”,这很笨拙/容易出错,因为现在有两个层次结构要保持同步。我怀疑数据绑定最终会被放弃。也许是 MVU,但我没有t 研究过。) 我同意仅在大多数情况下保留逻辑(例外情况,例如列表需要根据数据扩展某些项目)并在不触及 ViewModel 的情况下更新解决方案。 很遗憾,由于各种原因,我无法使用此解决方案。我需要数据模板选择器来选择不同的视图单元格。更重要的是,我还想尽可能地保留它 MVVM。在模型中具有扩展状态会打破这一点。我已经尝试了第一种方法,但无法使其正常工作,因为将 ViewCell.View 转换为堆栈面板总是会引发空异常 - 不知道为什么。我原以为会有一种相对简单的方法来做到这一点,它遵守 MVVM,但显然不是:/ 但是我很欣赏答案的努力! 我的错,我还在 ViewCell 上测试了 Tapped 事件,并在那里添加了一个 StackLayout 并对逻辑进行了编码。只要var child = cell.View as Expander 就可以了,还更新了答案。 嗨@DR_Bart,您尝试过更新的代码吗(更改了一行)。

以上是关于点击新项目时折叠 Xamarin ListView 中的所有项目的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin.Forms 不可点击的 ListView(移除选择涟漪效应)

如何在 Xamarin Forms 中滚动时折叠(隐藏或向上滑动)导航栏(标题栏)?

Xamarin Listview 仅添加 1 项我的列表中有 2 项

Xamarin表单ListView ItemTapped / ItemSelected在XAML上绑定命令

使用 Prism Xamarin 表单创建动态 TabbedPage

listview嵌套gridview,并实现grid元素部分显示以及点击展开与折叠