【问题标题】:No way to get ListView to show initial selected item无法让 ListView 显示初始选定项目
【发布时间】:2018-05-02 13:15:12
【问题描述】:

似乎没有办法让初始选择显示在 Xamarin Forms ListView 中。我看到这个问题已经被问过几次,但是在每种情况下都没有相关的答案,或者未回答的问题太复杂而无法正确分析,或者问题得到了回答但答案不起作用。所以我想我会提出这个问题的简化版本,希望有人能告诉我一个解决方法。一个解决方法就是可以做的所有事情,因为很明显 SelectedItem 不能被绑定并且不能从代码中设置。这是我检查过的 SO 问题...

:Why can't I set the SelectedItem property of Xamarin.Forms.ListView?

Xamarin Forms ListView SelectedItem Binding Issue

Xamarin.Forms ListView set SelectedItem by Code

Xamarin XAML ListView - How to select programatically

这里是 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"
         xmlns:local="clr-namespace:XamarinFormsBench"
         x:Class="XamarinFormsBench.ListViewPage1">
    <ContentPage.BindingContext>
        <local:ViewModel1/>
    </ContentPage.BindingContext>
    <ListView x:Name="MyListView" Margin="0,20,0,0"
        ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" 
          BindingContextChanged="MyListView_BindingContextChanged">
    </ListView>
</ContentPage>

这里是代码...

public class Item
{
    public Item(string name, string description)
    {
        Name = name;
        Description = description;
    }
    string Name { get; set; }
    string Description { get; set; }
    public override string ToString()
    {
        return Name + " = " + Description;
    }
}

public class ViewModel1 : INotifyPropertyChanged
{
    public ObservableCollection<Item> Items { get; set; }
    public ViewModel1()
    {

        Items = new ObservableCollection<Item>
        {
            new Item("Item 1","First item"),
            new Item("Item 2","Second item"),
            new Item("Item 3","Third item"),
            new Item("Item 4","Fourth item"),
            new Item("Item 5","Fifth item")
        };
        _selectedItem = Items[2];
    }
    Item _selectedItem;
    public event PropertyChangedEventHandler PropertyChanged;
    public Item SelectedItem
    {
        get
        {
            return _selectedItem;
        }
        set
        {
            _selectedItem = value;
            NotifyPropertyChanged(nameof(SelectedItem));
        }
    }
    public void NotifyPropertyChanged(string name)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ListViewPage1 : ContentPage
{
    public ListViewPage1()
    {
        InitializeComponent();
    }
    public ViewModel1 ViewModel
    {
        get
        {
            return BindingContext as ViewModel1;
        }
    }

    private void MyListView_BindingContextChanged(object sender, EventArgs e)
    {
    //         MyListView.SelectedItem = ViewModel.SelectedItem;
    }
}

我的期望是出现 5 个项目的列表,并突出显示第 3 个项目。发生的情况是出现 5 个项目,但没有突出显示任何项目。绑定显然有效,因为每次单击项目时都会更新所选项目。

现在,如果我删除绑定并尝试通过取消注释接近末尾的行来在代码中设置所选项目,那也不起作用。

所以我没有想法。我一直在研究模拟鼠标点击,但这确实超出了我愿意去的地方。

我已在 UWP 和 Android 上运行此代码。没试过iOS。

【问题讨论】:

  • 尝试将_selectedItem = Items[2]; 更改为SelectedItem = Items[2];。当您直接编辑私有字段时,您会丢失 propertyChange 事件通知。
  • 试过了。没有变化,特别是因为该代码位于视图模型构造函数中,因此属性更改事件为空。我还将代码添加到绑定上下文更改的事件处理程序中。我还将 SelectedItem 设置为 null,然后返回 Items[2] 仍然无效。我什么都试过了。
  • 好的。尝试用另一个 ItemsControl 替换 ListView。
  • ItemsView 你的意思是?集合视图中除了 ListView 之外只有 Picker 和 TableView。这些都不是 ListView 的替代品。

标签: c# xamarin xamarin.forms


【解决方案1】:

我刚刚创建了一个快速测试解决方案,这一切都适用于 iOS 和 Android。

不同之处在于我使用 FreshMvvm 来绑定 View 和 ViewModel 以及 PropertyChanged.Fody 来自动通知。

这表明是您的绑定或属性更改导致了问题。

这是视图模型

[AddINotifyPropertyChangedInterface]
public class MainPageModel : FreshBasePageModel
{
    public MainPageModel()
    {
        Items = new ObservableCollection<Item>
        {
            new Item("Item 1","First item"),
            new Item("Item 2","Second item"),
            new Item("Item 3","Third item"),
            new Item("Item 4","Fourth item"),
            new Item("Item 5","Fifth item")
        };

        SelectedItem = Items[2];
    }

    public ObservableCollection<Item> Items { get; set; }

    public Item SelectedItem { get; set; }
}

还有风景

<?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="ScratchPad.Pages.MainPage"
             Title="List Test">

    <ListView ItemsSource="{Binding Items}"
              SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    </ListView>

</ContentPage>

App.xaml.cs 只是为了衡量

public partial class App : Application
{
    public App()
    {
        InitializeComponent();

        var page = FreshPageModelResolver.ResolvePageModel<MainPageModel>();
        var nav = new FreshNavigationContainer(page);
        MainPage = nav;

    }

    ...
}

编辑“纯”Xamarin 表单代码

这里是视图

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:selectedItemTest="clr-namespace:SelectedItemTest;assembly=SelectedItemTest"
             x:Class="SelectedItemTest.MainPage"
             Title="List Test">

    <ContentPage.BindingContext>
        <selectedItemTest:MainPageModel/>
    </ContentPage.BindingContext>

    <ListView ItemsSource="{Binding Items}"
              SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
    </ListView>

</ContentPage>

还有视图模型

public class MainPageModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

    public ObservableCollection<Item> Items { get; set; }

    public MainPageModel()
    {
        Items = new ObservableCollection<Item>
        {
            new Item("Item 1","First item"),
            new Item("Item 2","Second item"),
            new Item("Item 3","Third item"),
            new Item("Item 4","Fourth item"),
            new Item("Item 5","Fifth item")
        };

        SelectedItem = Items[2];
    }

    private Item _selectedItem;
    public Item SelectedItem
    {
        get
        {
            return _selectedItem;
        }
        set
        {
            _selectedItem = value;
            OnPropertyChanged(nameof(SelectedItem));
        }
    }
}

【讨论】:

  • 谢谢史蒂夫。目前对第 3 方解决方案不感兴趣。我想让基本的机器工作。你能用代码更新你的答案吗?如果它太大而无法放入答案中……那说明不是吗?
  • 添加了代码。 FreshMvvm 非常轻量级。只需粘合用于连接视图和视图模型、一个小型 IOC 容器和一些辅助方法。 PropertyChanged.Fody 有助于删除所有属性更改样板。只是顶部的一个属性。
  • 看起来很有趣。我会调查的。我仍然希望看到使用纯 Xamarin Forms 的解决方案。除非我弄错了,否则这是一个需要修复的严重错误。事实上,考虑到多年来已经提出了同样的问题,这表明这是另一个 Xamarin 永久错误,其中有很多。 Charles Petzold 的书第 19 章中的 ListViewArray 示例将 SelectedItem 绑定到 BoxView 控件,这很有效!所以这是一个标准的大规模 kluge 的想法:将 ListView 选定项目绑定到一个标签,然后将标签绑定到其他东西。
  • 刚刚为使用 Pure Xamarin Forms 的解决方案添加了代码。工作。
  • 您使用的是什么版本的 Xamarin Forms?
【解决方案2】:

好的,事实证明这只是 UWP 上的一个问题。让 UWP 工作的解决方法如下 ListViewPage1 :

    protected override void OnAppearing()
    {
        base.OnAppearing();
        // *STANDARD MASSIVE KLUGE* Needed to get initial selection to show.
        Item m = MyListView.SelectedItem as Item;
        MyListView.SelectedItem = null;
        MyListView.SelectedItem = m;
    }

【讨论】:

    【解决方案3】:

    你为什么不尝试这样的事情:

                List<TodoItem> items = await todoTable.OrderByDescending(todoItem => todoItem.CreatedAt).ToListAsync();
    
    
                listView.Items.Clear();
                if (items.Count > 0)
                {
                    foreach (var item in items)
                    {
                        string row = "";
                        row += $"Name: {item.Text}" + $" created at {item.CreatedAt.ToLocalTime()}";
                        listView.Items.Add(row);
                    }
                    int selectedItem = 2;
                    if(items.Count > selectedItem)
                        listView.SelectedIndex = selectedItem;
                }
    

    我的代码从 Azure 表中获取数据,但它应该以相同的方式处理任何类型的数据。您可以从任何来源加载索引或对其进行硬编码。

    查看此链接:https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.ListView

    【讨论】:

      【解决方案4】:

      此问题应在撰写本文时在 Xamarin.Forms 主分支上修复。参考here

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-28
        • 1970-01-01
        • 1970-01-01
        • 2018-10-11
        • 1970-01-01
        • 2010-11-12
        • 1970-01-01
        相关资源
        最近更新 更多