【问题标题】:ListView ItemSelected open detail page MVVMListView ItemSelected 打开详情页 MVVM
【发布时间】:2018-01-03 09:44:13
【问题描述】:

在学习 xamarin 的个人项目中工作时,卡在打开有关我从 API 获得的所选项目的详细页面。 API,它返回一个这样的数组:

{
  "Restaurant": [
 {
   "Address": "Route Bounes Aires",
   "RestaurantID": "1",
   "RestaurantName": "John Doe",
   "City": "Lorem Ipsum"
 }
 {
   "Address": "Route Bounes Aires",
   "RestaurantID": "2",
   "RestaurantName": "John Doe",
   "City": "Lorem Ipsum"
 }]

我设法使用 MVVM 模式将这些信息绑定到列表视图中。现在我似乎无法打开所选项目的详细页面。 这是我到目前为止所拥有的: restaurantviewmodel.cs

public class RestaurantViewModel : INotifyPropertyChanged
{
    Service _services = new Service();
    List<Restaurant> _restaurant;
    public List<Restaurant> Restaurant
    {
        get { return _restaurant; }
        set
        {
            if (value == _restaurant) return;
            _branches = value;
            OnPropertyChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

    public ICommand ReastaurantCommand
    {
        get
        {
            return new Command(async () =>
            {
                Reastaurant = await _apiServices.GetReastaurant();
                await Application.Current.MainPage.Navigation.PushAsync(new ReastaurantPage(_restaurant));
            });
        }
    }        
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

service.cs

public async Task<List<Reastaurant>> GetReastaurant()
    {

        ListReastaurant restaurant = null;
        try { 
            var client = new HttpClient();
            client.DefaultRequestHeaders.Add("xxx", "xxx");
            client.DefaultRequestHeaders.Add("xxx", xxx);

            HttpContent content = new StringContent("");
            content.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            var response = await client.PostAsync("https:www.here/goes/the/call/to/the/api", content);
            response.EnsureSuccessStatusCode();
            string json = await response.Content.ReadAsStringAsync();
            restaurant = JsonConvert.DeserializeObject<ListReataurantDetails>(json);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message.ToString());
        }
        return restaurant.Restaurant;
    }

模型 restaurant.cs

public class Restaurant
{
    public string Address { get; set; }
    public string restaurantID { get; set; }
    public string RestaurantName  { get; set; }
    public string City  { get; set; }
}

餐厅.xaml 页面:

<ListView x:Name="restaurantlistview"
              HasUnevenRows="True" ItemSelected="restaurantlistview_ItemSelected">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Padding="20, 10">
                        <Label  Text="{Binding RestaurantName}"
                                 FontSize="20"
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

restaurant.xaml.cs 背后的代码

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Restaurant : ContentPage
{
    public Restaurant(List<Models.Restaurant> restaurant)
    {
        InitializeComponent();
        NavigationPage.SetTitleIcon(this, "icon.png");
        restaurantlistview.ItemsSource = restaurant;
    }
     private async void restaurantlistview_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        await Navigation.PushAsync(new RestaurantSinglePageDetails());
    }
}

我该如何解决这个问题? 我想将一家餐厅的详细信息用于另一个页面,这样我就可以显示地址和城市,并使用这些信息来做不同的事情。我认为这很容易,我只是没有很好地掌握 mvvm 模式的概念。 为了澄清,我不是试图将所有数据传递到另一个页面,而只是试图访问有关single item(餐厅)的信息。 我真的需要一些帮助。谢谢大家!

===编辑===

public partial class RestaurantSinglePageDetails: ContentPage
{
  public RestaurantSinglePageDetails(Models.Restaurant res)
    {
        InitializeComponent();
        NavigationPage.SetTitleIcon(this, "logosmall.png");
        BindingContext = new RestaurantDetailsViewModel(res);
       //and here I'm supposed to have access to my selected restaurant.
    }
}

restaurantdetailsdviewmodel.cs

public class RestaurantDetailsViewModel : INotifyPropertyChanged
{
    // ==edit==
   Restaurant restaurant;
   public RestaurantDetailsViewModel(Restaurant restaurant)
   {
    this.restaurant = restaurant; // now we can use it in ViewModel
   }
   Service _services = new Service();
   List<Info> _info;
   public List<Info> Info
    {
        get { return _info; }
        set
        {
            if (value == _info) return;
            _info = value; 
            OnPropertyChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public ICommand GetInfoCommand
    {
        get
        {
            return new Command(async () =>
            {
                InfoData = await _apiServices.GetInfoData();
                await Application.Current.MainPage.Navigation.PushAsync(new SingleDetailsAboutPrice(InfoData, restaurant));
            });
        }
    }
}

我想在这里使用 RestaurantID: SingleDetailsAboutPrice.xaml.cs:

 Restaurant restaurant;
 public SingleDetailsAboutPrice(List<Models.InfoData> data, Restaurant restaurant)
    {
        InitializeComponent();
        this.restaurant = restaurant;
        //can't use the restaurantid here; 
        //some code goes here;
    }

错误

给定的键不在字典中

【问题讨论】:

  • Restaurant 类中的构造函数在哪里?
  • 试图传递单个项目的数据,而不是另一个页面中的所有项目。我需要另一个json吗?还是我需要其他服务? @evz 如何传递参数?
  • @qubuss 我没有。我应该创建它吗?
  • @John 是的。看答案

标签: c# xaml xamarin mvvm xamarin.forms


【解决方案1】:

在你的 contentPage 餐厅类中你应该

初始化组件();

在构造函数类中

XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Restaurant : ContentPage
{
    public Restaurant(List<Models.Restaurant> restaurant)
    {
        InitializeComponent();
        NavigationPage.SetTitleIcon(this, "icon.png");
        restaurantlistview.ItemsSource = restaurant;
    }
    private async void restaurantlistview_ItemSelected(object sender,   SelectedItemChangedEventArgs e)
    {
    //edit
    var restaurant = (Restaurant)sender;
    await Navigation.PushAsync(new RestaurantSinglePageDetails(restaurant));
    }
}

获取您选择的项目:

var restaurant = (Restaurant)sender;

接下来你必须创建新页面

public partial class RestaurantSinglePageDetails: ContentPage
{
    Restaurant res;
    public RestaurantSinglePageDetails(Restaurant res)
    {
        InitializeComponent();
        this.res = res; 

        //and here you have access to your selected restaurant. 
    }
}

您可以从所有班级访问的资源。所以当你移动到另一个页面时,你可以把这个 res。

===编辑===

如果我的意思正确,您想将 RestaurantID 传递给 SingleDetailsAboutPrice,因此您必须将其传递给 RestaurantDetailsViewModel,然后如果您单击按钮,则将其传递给 SingleDetailsAboutPrice(RestaurantId)

public partial class RestaurantSinglePageDetails: ContentPage
{
    Restaurant res;
    public RestaurantSinglePageDetails(Restaurant res)
    {
        InitializeComponent();
        BindingContext = new RestaurantDetailsViewModel(item); //now you have access to restaurant in your viewModel. In this way you don't need use BindingContext in XAML
        this.res = res; 


        //and here you have access to your selected restaurant. 
    }
}

现在在RestaurantDetailsViewModel 中,我们需要使用Restaurant 创建构造函数

public class RestaurantDetailsViewModel : INotifyPropertyChanged
{
    Service _services = new Service();
    Restaurant restaurant;
    public RestaurantDetailsViewModel(Restaurant restaurant)
    {
        this.restaurant = restaurant; // now we can use it in ViewModel
    }
    List<Info> _info;
    public List<Info> Info
    {
        get { return _info; }
        set
        {
            if (value == _info) return;
            _info = value; 
             OnPropertyChanged();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public ICommand GetInfoCommand
    {
        get
        {
            return new Command(async () =>
            {
                InfoData = await _apiServices.GetInfoData();
                await  Application.Current.MainPage.Navigation.PushAsync(new  SingleDetailsAboutPrice(restaurant)); // or if you want u can pass only restaurant.restaurantID.
            });
        }
    }
}

SingleDetailsAboutPrice 中,我们使用Restaurant 或仅RestaurantId 创建构造函数

public partial class Restaurant : ContentPage
{
    Restaurant restaurant;
    public SingleDetailsAboutPrice(Restaurant restaurant) 
    {
        InitializeComponent();
        this.restaurant = restaurant;
    }

    String restaurantID;
    // if you want only restaurantID
    public SingleDetailsAboutPrice(String restaurantID) 
    {
        InitializeComponent();
        this.restaurantID = restaurantID;
    }
}

【讨论】:

  • 是的,谢谢,我已经想通了。无论如何,这是解决问题的好方法吗?!有没有其他方法可以解决它?谢谢@qubuss
  • 我觉得挺好的,也许还有别的办法,但我不知道。 :P
  • @GeraldVersluis 为什么?如果我们使用 MVVM 制作 RestaurantSinglePageDetails,我们会将餐厅传递给视图模型,它应该是。好吧,你是对的,因为我们应该将选定的项目移动到 viewModel 类并创建绑定上下文。并且列表的项目来源必须在模型视图中。
  • 您已经回答了自己的评论;) 不应涉及代码隐藏代码
  • 无论如何,谢谢你的帮助。如果你不介意问,还有一件事。如果我想在另一个页面中使用这些信息怎么办?例如从RestaurantSinglePageDetails 到另一个页面。 @qubuss
猜你喜欢
  • 2018-03-10
  • 2017-02-04
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
  • 1970-01-01
  • 2019-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多