无法让ListView显示初始选定的项目

时间:2017-11-19 02:03:15

标签: c# xamarin xamarin.forms

似乎无法在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上运行此代码。 Haven没有尝试过iOS。

4 个答案:

答案 0 :(得分:1)

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

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

这表明导致问题的是你的绑定或属性变化。

这是viewmodel

[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;

    }

    ...
}

enter image description here

编辑“Pure”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));
        }
    }
}

答案 1 :(得分:1)

好的,事实证明这只是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;
    }

答案 2 :(得分:0)

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

            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

答案 3 :(得分:0)

这应该在Xamarin.Forms主分支编写时修复。请参阅here以供参考。