问题描述
这是我的第一个问题,大家好。 我正在使用 Prism 在 Xamarin.Forms 中开发移动应用程序。我创建了 ListView,其中显示了数据库中的数据。
当用户点击所选行时,应用应导航到新视图并从 ListView 传递所选项目。
<ListView x:Name="defectsBase"
RowHeight="65"
ItemsSource="{Binding defects}"
ItemSelected="ShowDetailsEvent"
IsPullToRefreshEnabled="true"
RefreshCommand="{Binding Refresh}"
IsRefreshing="{Binding IsRefreshing}">
代码后端:
async void ShowDetailsEvent(object sender,EventArgs e)
{
var myListView = (ListView)sender;
var myItem = myListView.SelectedItem;
var p = new NavigationParameters();
p.Add("selectedDefect",myItem);
await _navigationService.NavigateAsync("DefectDetailsView",p);
}
遗憾的是,该应用对按下 ListView 中的选定行没有响应。
解决方法
正如我所看到的,您已经在使用 Prism
并且您有一个包含项目的列表页面,并且您想根据用户在 ListView 中点击的选定/录制/选择项目导航到某些详细信息页面。
我们的想法是将尽可能多的代码和逻辑移动到视图模型中并保留我们的代码。使用 Prism
和 EventToCommand
行为很容易解决这个问题。
在下面的示例和答案中,我将向您展示如何用几行代码和一个很好的代码方法来解决这个问题。
首先,我建议您使用 EventToCommand
行为,您可以将其包含在棱镜 xmlns 中,如下所示:xmlns:prism="http://prismlibrary.com"
,稍后,您可以将其与 ListView 一起使用。
从 ListView 中移除 ItemSelected 事件并将关于它的标记移至 <ListView.Behaviors>
部分。这是我的 ListView
代码示例,它绑定到某些 ObserverableCollection
汽车模型:
<ListView ItemsSource="{Binding Cars}">
<ListView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<prism:EventToCommandBehavior EventName="ItemTapped"
Command="{Binding SelectedCarCommand}"
EventArgsParameterPath="Item" />
</ListView.Behaviors>
此处的主要部分是 <ListView.Behaviors>
,您可以在其中看到我正在绑定到 SelectedCarCommand,当用户点击列表中的某些项目时,该命令将被调用。我为此使用了 ItemTapped
事件,并将列表中的当前“录音”项目作为参数传递。
为了在此页面的视图模型中遵循此 XAML 部分,我声明了 DelegateCommand
和将在调用命令时调用的方法。视图模型部分如下所示:
这是我的 CarListPageViewModel,看看 DelegateCommand 和 SelectedCar 方法。
public class CarListPageViewModel
{
private readonly INavigationService _navigationService;
public ObservableCollection<Car> Cars { get; set; }
public DelegateCommand<Car> SelectedCarCommand { get; private set; }
public CarListPageViewModel(INavigationService navigationService,IDataProvider dataProvider)
{
_navigationService = navigationService;
// Insert test data into collection of Cars
Cars = new ObservableCollection<Car>(dataProvider.GetData());
SelectedCarCommand = new DelegateCommand<Car>(SelectedCar);
}
private async void SelectedCar(Car selectedCar)
{
NavigationParameters navigationParameters = new NavigationParameters
{
{ "selectedCar",selectedCar }
};
await _navigationService.NavigateAsync(nameof(CarDetailsPage),navigationParameters);
}
}
如您所见,我们使用将要传递的参数类型定义了 DelegateCommand
,在我的例子中,这是 Car 类,与我们在 ListView 中的项目相同。
在构造函数中,我进行了初始化并定义了将被调用的方法,该方法有一个 Car 类型的参数。
当用户点击 ListView 中的一项时,SelectedCar(方法)将被调用,我们可以使用 NavigationParameters
和 NavigationService
将数据传递到下一个视图。
为了检索传递的数据,我们可以在详细信息视图模型中使用 INavigationAware
并使用 OnNavigatedTo
方法访问正在传递的数据。
这是我的 CarDetailsPageViewModel,看看 OnNavigatedTo
方法。
public class CarDetailsPageViewModel : BindableBase,INavigationAware
{
private string carTitle;
public string CarTitle
{
get { return carTitle; }
set { SetProperty(ref carTitle,value); }
}
private string photoUrl;
public string PhotoUrl
{
get { return photoUrl; }
set { SetProperty(ref photoUrl,value); }
}
public CarDetailsPageViewModel() { }
public void OnNavigatedTo(INavigationParameters parameters)
{
if (parameters.ContainsKey("selectedCar"))
{
Car car = parameters.GetValue<Car>("selectedCar");
if (car != null)
{
CarTitle = $"{car.Make} {car.Model}";
PhotoUrl = car.PhotoUrl;
}
}
}
public void OnNavigatedFrom(INavigationParameters parameters) { }
}
从这个答案和例子中,你可以看到:
- 如何将
EventToCommand
行为与ListView
结合使用 - 定义并使用带有传递参数的
DelegateCommand
- 如何导航到另一个视图并传递导航参数和
- ...最后如何访问传递的数据。
您可以在我的 GitHub 个人资料 here 上找到代码和此示例。
希望这个回答对你有帮助!
祝你在编码方面好运! ?