简体   繁体   English

如何使用 MVVM 和 Xamarin.Forms ListView ItemSelected 事件来检索所选项目的绑定属性?

[英]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.我个人更喜欢在视图中处理逻辑,因为它使代码更简单。

1. Handle Logic In The View 1.在视图中处理逻辑

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

2. Handle Logic In The View Model 2. 处理视图模型中的逻辑

View看法

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);
    }
}

ViewModel视图模型

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.

相关问题 如何通过打开上下文操作菜单从ListView中获取所选项目? (Xamarin.Forms) - How do I get the selected item from a ListView by opening the context actions menu? (Xamarin.Forms) 如何更改listview所选项目的文本颜色Xamarin.forms - How to change the listview selected item text color Xamarin.forms Xamarin.Forms 中 ListView 上的 ItemTapped 和 ItemSelected 事件有什么区别? - What's the difference between the ItemTapped and the ItemSelected event on a ListView in Xamarin.Forms? 在 ListView 上选择的项目以及有关 object 的更多信息(Xamarin.Forms、C #) - ItemSelected on ListView and more information about the object (Xamarin.Forms, C #) 如何使用 XAML 在 Xamarin.Forms 的 ListView 中选择一个项目 - How can I select an item in a ListView in Xamarin.Forms with XAML Xamarin.Forms 如何禁用 ListView 上的单击动画 - Xamarin.Forms How do I disable click animation on ListView 获取Xamarin.Forms中ListView的所选项的ID - Get id of selected item of ListView in Xamarin.Forms 在 Xamarin.Forms 中检索 ListView 所选项目值 - Retrieving ListView selected item value in Xamarin.Forms 如何选择项目 MVVM 列表视图 - Xamarin 形式 - How selected item MVVM listview - Xamarin form Xamarin.Forms ListView与CustomViewCell禁用选定的项目颜色 - Xamarin.Forms ListView with CustomViewCell disable Selected Item Color
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM