Xamarin.Forms:获取列表视图的所有单元格/项目

tes*_*ing 5 listview xamarin.ios xamarin xamarin.forms

我想对ListView中显示的所有单元格进行一些更改.因此,我想获得所有细胞或物品.例如

this.listView.ItemSource.Items
Run Code Online (Sandbox Code Playgroud)

项目在上面的代码不存在.此外,我没有找到任何选项,ListView或者ItemSource可以做到这一点.是否可以获得所有细胞/物品?如果没有,我还有什么其他选择来改变它们被加载后细胞的外观?例如,用于更改文本或布局.

Mar*_*hel 14

我可能迟到了派对,但这是使用System.Reflection的另一种方法.无论如何,我建议只在无法进行数据绑定的情况下使用它并作为最后的选择.

对于给定的ListView

<ListView x:Name="connectionsListView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ItemSelected="OnConnectionSelect">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell Height="40">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="50"/>
                    </Grid.ColumnDefinitions>
                    <customs:MyViewClass Grid.Column="0"/>
                </Grid>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
    <ListView.Footer>
        <ContentView />
    </ListView.Footer>
</ListView>
Run Code Online (Sandbox Code Playgroud)

您可以通过抓取"TemplatedItems"属性,将其强制转换ITemplatedItemsList<Cell>并迭代(View)单元格来爬行ListView .

IEnumerable<PropertyInfo> pInfos = (connectionsListView as ItemsView<Cell>).GetType().GetRuntimeProperties();
var templatedItems = pInfos.FirstOrDefault(info => info.Name == "TemplatedItems");
if (templatedItems != null)
{
  var cells = templatedItems.GetValue(connectionsListView);
    foreach (ViewCell cell in cells as Xamarin.Forms.ITemplatedItemsList<Xamarin.Forms.Cell>)
    {
        if (cell.BindingContext != null && cell.BindingContext is MyModelClass)
        {
            MyViewClass target = (cell.View as Grid).Children.OfType<MyViewClass>().FirstOrDefault();
            if (target != null)
            {
               //do whatever you want to do with your item... 
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:既然有人问,如果(!cell.BindingContext = NULL && cell.BindingContext是MyModelClass)基本上是一个保障,以防止访问不存在的观点,例如,如果ListView控件尚未填充呢.

如果不需要检查BindingContext是否为特定模型类,则将行减少为就足够了

if (cell.BindingContext != null)
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢这种方法,到目前为止,唯一遇到的问题是使用分组列表视图时。“单元格”将仅保存组标题。仍然很整齐 (2认同)

Sve*_*übe 5

通常,您不直接触摸细胞.相反,如果可能的话,你会尝试通过数据绑定来做所有事情.

让我们使用XAML中定义的以下页面:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="App6.Page1">
  <ListView x:Name="myList"
            BackgroundColor="Gray"
            ItemsSource="{Binding MyItems}"
            HasUnevenRows="true"
            RowHeight="-1">
    <ListView.ItemTemplate>
      <DataTemplate>
        <ViewCell>
          <ViewCell.View>
            <StackLayout
                        HorizontalOptions="FillAndExpand"
                        VerticalOptions="StartAndExpand"
                        Padding="15, 10, 10, 10"
                        BackgroundColor="White">

              <Label  Text="{Binding Title}"
                      FontSize="18"
                      TextColor="Black"
                      VerticalOptions="StartAndExpand"/>
            </StackLayout>
          </ViewCell.View>
        </ViewCell>
      </DataTemplate>
    </ListView.ItemTemplate>
  </ListView>
</ContentPage>
Run Code Online (Sandbox Code Playgroud)

在您的页面中,将ViewModel设置为BindingContext.

public partial class Page1 : ContentPage
{
    public Page1()
    {
        InitializeComponent();
        BindingContext = new Page1ViewModel();
    }
}
Run Code Online (Sandbox Code Playgroud)

并且您的ViewModel包含MyItemsObservableCollection 中的Items ,这意味着如果添加或删除Items,视图会更新.此属性绑定为List的ItemsSource(请参阅XAML :) ItemsSource="{Binding MyItems}".

class Page1ViewModel : INotifyPropertyChanged
{
    private ObservableCollection<MyItem> _myItems = new ObservableCollection<MyItem>();
    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<MyItem> MyItems
    {
        get { return _myItems; }
        set
        {
            _myItems = value;
            OnPropertyChanged();
        }
    }

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public Page1ViewModel()
    {
        MyItems.Add(new MyItem { Title = "Test" });
        MyItems.Add(new MyItem { Title = "Test2" });
        MyItems.Add(new MyItem { Title = "Test3" });
        MyItems.Add(new MyItem { Title = "Test4" });
        MyItems.Add(new MyItem { Title = "Test5" });
    }

    public void ChangeItem()
    {
        MyItems[1].Title = "Hello World";
    }
}
Run Code Online (Sandbox Code Playgroud)

对于每个Item,您有一个表示一个单元格数据的对象.该项目的类型实现INotifyPropertyChanged.这意味着它会通知哪个属性已被更改.数据绑定机制注册到此事件,并在引发视图时更新视图.

public class MyItem : INotifyPropertyChanged
{
    private string _title;

    public string Title
    {
        get { return _title; }
        set
        {
            _title = value;
            OnPropertyChanged(); // Notify, that Title has been changed
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您现在更改其中一个项目,例如通过呼叫ChangeItem().然后第二个单元格的Label将更新为"Hello World",因为它绑定到Title(请参阅XAML Text="{Binding Title}").

所有这些背后的一般思想称为MvvM模式,您希望将视图与视图逻辑和模型(数据/服务,...)分开.