[英]How do I use MVVM and Xamarin.Forms ListView ItemSelected event to to retrieve a bound property of the item selected?
I am using Xamarin.Forms and attempting to use the MVVM architecture.我正在使用 Xamarin.Forms 并尝试使用 MVVM 架构。
I have a ContentPage that has a simple List View on it.我有一个内容页面,上面有一个简单的列表视图。 The List View has its item source property bound to my ViewModel.
列表视图的项目源属性绑定到我的 ViewModel。 I am able to populate the list just fine.
我能够很好地填充列表。 All of the items display as they should.
所有项目都按其应有的方式显示。
When I click on an item from the list, I need to navigate to a different page based on the item selected.当我单击列表中的一个项目时,我需要根据所选项目导航到不同的页面。 This is what is not working.
这是行不通的。 It will ONLY work if I reference my underlying Model directly (which is NOT what I want to do)
它只有在我直接引用我的基础模型时才有效(这不是我想要做的)
I have the ListView.ItemSelected event coded.我对 ListView.ItemSelected 事件进行了编码。 However, the Item Selected event can't determine what the "display_text" is of the List Item selected.
但是,Item Selected 事件无法确定所选列表项的“display_text”是什么。 How do I achieve this without having to reference my model directly from my View (Page)?
如何在不必直接从我的视图(页面)中引用我的模型的情况下实现这一点?
MainPage Code:主页代码:
public partial class MainPage : ContentPage
{
private int intPreJobFormID = 0;
public MainPage()
{
InitializeComponent();
BindingContext = new MainPageViewModel();
Label lblHeader = new Label
{
Text = "HW Job Assessments",
FontSize = ViewGlobals.lblHeader_FontSize,
HorizontalOptions = ViewGlobals.lblHeader_HorizontalOptions,
FontAttributes = ViewGlobals.lblHeader_FontAttributes,
TextColor = ViewGlobals.lblHeader_TextColor
};
//Create the Main Menu Items List View
var lvMain = new ListView
{
//Pull down to refresh list
IsPullToRefreshEnabled = true,
//Define template for displaying each item.
//Argument of DataTemplate constructor is called for each item. It must return a Cell derivative.
ItemTemplate = new DataTemplate(() =>
{
//Create views with bindings for displaying each property.
Label lblDisplayText = new Label();
lblDisplayText.SetBinding(Label.TextProperty, "display_text");
lblDisplayText.FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label));
//Return an assembled ViewCell.
return new ViewCell
{
View = new StackLayout
{
Padding = new Thickness(20, 5, 0, 0),
Orientation = StackOrientation.Horizontal,
Children =
{
new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Spacing = 0,
Children =
{
lblDisplayText
}
}
}
}
};
})
};
lvMain.SetBinding(ListView.ItemsSourceProperty, "MainMenuItems");
lvMain.ItemSelected += lvMain_ItemSelected;
}
private async void lvMain_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var lv = (ListView)sender;
if (e.SelectedItem == null)
{
return; //ItemSelected is called on deselection which results in SelectedItem being set to null
}
//var item = e.SelectedItem as TableMainMenuItems; //This is what I DON'T want to use because it references my Model directly.
var item = e.SelectedItem;
switch (item.display_text) //This is what I need. I can't get this unless I reference my Model "TableMainMenuItems" directly.
{
case "Forms List":
await Navigation.PushAsync(new FormsListPage());
break;
case "New Pre-Job":
await Navigation.PushAsync(new PreJobPage(intPreJobFormID));
break;
}
//Comment out if you want to keep selections
lv.SelectedItem = null;
}
}
MainPageViewModel Code: MainPageViewModel 代码:
public class MainPageViewModel
{
public int intPreJobFormID = 0;
private DatabaseApp app_database = ViewModelGlobals.AppDB;
private DatabaseFormData formdata_database = ViewModelGlobals.FormDataDB;
private IEnumerable<TableMainMenuItems> lstMaineMenuItems;
private IEnumerable<TableFormData> lstRecentJobs;
public string DisplayText { get; set; }
public IEnumerable<TableMainMenuItems> MainMenuItems
{
get { return lstMaineMenuItems; }
set
{
lstMaineMenuItems = value;
}
}
public IEnumerable<TableFormData> RecentJobs
{
get { return lstRecentJobs; }
set
{
lstRecentJobs = value;
}
}
public MainPageViewModel()
{
intPreJobFormID = app_database.GetForm(0, "Pre-Job Assessment").Id;
MainMenuItems = app_database.GetMainMenuItems();
RecentJobs = formdata_database.GetFormAnswersForForm(intPreJobFormID).OrderByDescending(o => o.date_modified);
}
}
There are 2 ways to retrieve the bound property of the item selected.有两种方法可以检索所选项目的绑定属性。
I personally prefer to handle the logic in the view because it keeps the code simpler.我个人更喜欢在视图中处理逻辑,因为它使代码更简单。
cast item
as your model type: var item = e.SelectedItem as TableMainMenuItems;
将
item
作为您的模型类型: var item = e.SelectedItem as TableMainMenuItems;
async void lvMain_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var listView = (ListView)sender;
listView.SelectedItem = null;
if (e?.SelectedItem is TableMainMenuItems item)
{
switch (item.display_text)
{
case "Forms List":
await Navigation.PushAsync(new FormsListPage());
break;
case "New Pre-Job":
await Navigation.PushAsync(new PreJobPage(intPreJobFormID));
break;
}
}
}
Use a Command<T>
to loosely couple the ItemSelected logic between the View and the View Model.使用
Command<T>
在视图和视图模型之间松散耦合 ItemSelected 逻辑。 Create an event
in the View Model that will fire when the View Model has completed the logic.在视图模型中创建一个
event
,当视图模型完成逻辑时将触发该event
。
public partial class MainPage : ContentPage
{
public MainPage()
{
var viewModel = new MainPageViewModel();
BindingContext = viewModel;
...
viewModel.NavigationRequested += (s,e) => Device.BeginInvokeOnMainThread(async () => await Navigation.PushAsync(e));
}
...
void lvMain_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var listView = (ListView)sender;
listView.SelectedItem = null;
var viewModel = (MainPageViewModel)BindingContext;
viewModel.ListViewItemSelectedCommand?.Invoke(e);
}
}
public class MainPageViewModel
{
//...
Command<SelectedItemChangedEventArgs> _listViewItemSelectedCommand;
//...
public event EventHandler<Page> NavigationRequested;
//...
public Command<SelectedItemChangedEventArgs> ListViewItemSelectedCommand => _listViewItemSelectedCommand ??
(_listViewItemSelectedCommand = new Command<SelectedItemChangedEventArgs>(ExecuteListViewItemSelectedCommand));
//...
void ExecuteListViewItemSelectedCommand(SelectedItemChangedEventArgs e)
{
var item = e as TableMainMenuItems;
switch (item?.display_text)
{
case "Forms List":
OnNavigationRequested(new FormsListPage());
break;
case "New Pre-Job":
OnNavigationRequested(new PreJobPage(0));
break;
}
}
void OnNavigationRequested(Page pageToNavigate) => NavigationRequested?.Invoke(this, pageToNavigate);
//...
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.