首页 > 解决方案 > 从另一个 NavPage 的 ListView 将 SelectedItem 绑定到根 NavPage UI 不起作用

问题描述

我想使用正确的导航栏按钮作为我的 ListView 的过滤器功能。我的第一种方法是下拉列表,但由于这在 iOS 中是不可能的,所以我尝试使用 NuGet 包绕过它Rg.Plugins.Popup(我不想创建 CustomRenderer)。到目前为止,这一切都很好。

从我的其他 ListView 中选择后,我的 UI 没有更新。关于正确调试我的值更改。

这是我的视图模型:

public ProcessesPageViewModel()
        {
            Location = new Location { Name = "Default", Filter = "Default" };
            AsyncCreateListLocations();
        }

AsyncCreateListLocations() 只是一个任务:

void CreateListLocations()
    {
        downloadLocations = new DownloadLocations();
        LocationList = downloadLocations.DownloadJSON().OrderBy(x => x.Name).ToList();
    }

private Location _location;
public Location Location
    {
        get => _location;
        set
        {
            SetValue(ref _location, value);
        }
    }

我的 XAML 来自根 ListView,过滤器应该稍后应用(尚未实现):

<ContentPage.ToolbarItems>
    <ToolbarItem Text="{Binding Location.Name}" Clicked="Clicked_Location"/>
</ContentPage.ToolbarItems>

现在这是我的 PopUp 页面,其位置为 ListView:

<ListView x:Name="ProcessesListView"
              ItemsSource="{Binding LocationList}"
              SelectedItem="{Binding Location}"
              WidthRequest="100"
              HeightRequest="200"
              ItemSelected="OnItemSelected"
              VerticalOptions="Center">

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Label Margin="5" FontAttributes="Bold" VerticalOptions="FillAndExpand" Grid.Row="0" Grid.ColumnSpan="2" Text="{Binding Name}" />
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>


async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
        {
            await Navigation.PopPopupAsync();
        }

使用 Acr.UserDialogs 编辑:

using Acr.UserDialogs;
using MyProject.Models;
using MyProject.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace MyProject.ViewModels
{
    public class MyViewModel : BaseViewModel
    {
        private IUserDialogs userDialogs;
        public MyViewModel(IUserDialogs userDialogs)
        {
            this.userDialogs = userDialogs;
        }
        DownloadProcesses downloadProcesses;
        DownloadLocations downloadLocations;
        public Command LoadItemsCommand { get; set; }
        public Command ToolbarItemCommand { get; set; }
        public MyViewModel()
        {
            Location = new Location { Name = "Default", Filter = "Default" };
            LoadItemsCommand = new Command(ExecuteLoadItemsCommand);
            ToolbarItemCommand = new Command(SetLocation);
            AsyncCreateListProcesses();
            AsyncCreateListLocations();
        }
        void CreateListProcesses()
        {
            downloadProcesses = new DownloadProcesses();
            ProcessList = downloadProcesses.DownloadJSON().OrderByDescending(x => DateTime.Parse(x.Datum)).ThenByDescending(x => DateTime.Parse(x.Zeit)).ToList();
        }
        void CreateListLocations()
        {
            downloadLocations = new DownloadLocations();
            LocationList = downloadLocations.DownloadJSON();
            //LocationList = downloadLocations.DownloadJSON().OrderBy(x => x.Name).ToList();            
        }
        async void SetLocation()
        {
            var selectedOptionDesc = await this.userDialogs.ActionSheetAsync("MyTitle", "MyCancelButtonText", null, null, this.LocationList.Select(l => l.Name).ToArray());
            if (string.IsNullOrEmpty(selectedOptionDesc))
                return;

            var selectedOption = this.LocationList.FirstOrDefault(l => l.Name == selectedOptionDesc);
            if (selectedOption == null)
                return;

            Xamarin.Forms.Device.BeginInvokeOnMainThread(() => this.Location = selectedOption);
        }
        public Task AsyncCreateListProcesses()
        {
            return Task.Run(() => CreateListProcesses());
        }
        public Task AsyncCreateListLocations()
        {
            return Task.Run(() => CreateListLocations());
        }        
        async void ExecuteLoadItemsCommand()
        {
            if (IsBusy)
                return;

            IsBusy = true;

            try
            {
                await AsyncCreateListProcesses();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                IsBusy = false;
            }
        }

        private List<Process> _processList;
        public List<Process> ProcessList
        {
            get => _processList;
            set => SetValue(ref _processList, value);
        }
        private List<Location> _locationList;
        public List<Location> LocationList
        {
            get => _locationList;
            set => SetValue(ref _locationList, value);
        }
        private Location _location;
        public Location Location
        {
            get => _location;
            set
            {
                if (value != null)
                {
                    SetValue(ref _location, value);
                } 
            }
        }
    }

}

标签: c#xamlxamarin.forms

解决方案


我建议您使用Acr.UserDialogs它真的很容易使用并且允许自定义。

为了执行您想要安装包的操作,请在您的 Android 项目的主要活动中对其进行初始化:

UserDialogs.Init(() => (Activity)Forms.Context)

将您的 IUserDialogs 注入您的ViewModel

private IUserDialogs userDialogs;

public MyViewModel(IUserDialogs userDialogs)
{
    this.userDialogs = userDialogs;
}

并致电:

var selectedOptionDesc = await this.userDialogs.ActionSheetAsync("MyTitle", "MyCancelButtonText", null, null, this.LocationList.Select(l => l.Description).ToArray());
if (string.IsNullOrEmpty(selectedOptionDesc))
    return;

var selectedOption = this.LocationList.FirstOrDefault(l => l.Description == selectedOptionDesc);
if (selectedOption == null)
    return;

Xamarin.Forms.Device.BeginInvokeOnMainThread(() => this.Location = selectedOption);

如果您没有依赖注入引擎,那么您可以替换this.userDialogs.ActionSheetAsync(...)为:

UserDialogs.Instance.ActionSheetAsync(...)

如果您仍然想使用您的库,可能它不会更新您的视图,因为您没有Location在 MainThread 中设置属性,因此您必须将该 set 包装在 aXamarin.Forms.Device.BeginInvokeOnMainThread(() => ...);中以在 MainThread 中执行此操作,因此您View会收到更改通知。

HIH


推荐阅读