何时使用Xamarin绑定,而不是将对象传递给页面构造函数? [英] When to use Xamarin bindings as opposed to passing objects to page constructors?

查看:46
本文介绍了何时使用Xamarin绑定,而不是将对象传递给页面构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我遇到了一个问题,我想以一种我认为非常标准的方式在应用程序中传递数据,但是我找不到与我想做的事情相似的示例或示例.

例如,我有一个类型为person的应用程序.

 公共类Person{公共字符串名称;公共诠释时代;公众人物(字符串名称,整数年龄){名称=名称;年龄=年龄;}} 

我想创建一个人卡列表,每个卡都显示该人的信息.然后,当点击该卡时,它将带您到包含该人的信息的新页面.我已经在下面的代码中实现了此功能,但是我尝试过的xamarin原理不起作用,因此它更多地依赖于我的c#技能,我觉得这不是编写xamarin代码的标准方法.

我已将工作项目上传到

So I have a problem where I want to pass data around my application in what I thought would have been a very standard way, but I'm unable to find any samples or examples that are similar to what I want to do.

For example, I have an application with the type person.

public class Person
    {
        public string Name;
        public int Age;

        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
    }

I want to create a list of person cards, each displaying the person's information. Then, when the card is tapped, it will take you to a new page containing that person's information. I have achieved this functionality in the following code, however the xamarin principles I tried didn't work, so it relies more on my c# skills, and I feel like this is not the standard way to write xamarin code.

I have uploaded the working project to a GitHub repo.

So my questions are, what are the disadvantages of my approach, and how would I implement the same functionality using more standard tools like bindings.

PersonCard.xaml:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomViewListTest.Views.PersonCard"
             xmlns:System="clr-namespace:System;assembly=mscorlib">

    <ContentView.ControlTemplate>
        <ControlTemplate>
            <Frame BorderColor="#3F3F3F" Margin="2">
                <Frame.GestureRecognizers>
                    <TapGestureRecognizer Tapped="OnTapped"/>
                </Frame.GestureRecognizers>
                <StackLayout>
                    <Label Text="{TemplateBinding Name}"></Label>
                    <Label Text="{TemplateBinding Age}"></Label>
                </StackLayout>
            </Frame>
        </ControlTemplate>
    </ContentView.ControlTemplate>
</ContentView>

PersonCard.cs

[XamlCompilation(XamlCompilationOptions.Compile)] public partial class PersonCard : ContentView {

    public PersonCard(Person person) 
    {
        Person = person;
        InitializeComponent();
    }

    public PersonCard()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty PersonProperty =
       BindableProperty.Create(nameof(Person), typeof(Person), typeof(PersonCard), null);

    public static readonly BindableProperty NameProperty = 
        BindableProperty.Create(nameof(Name), typeof(string), typeof(PersonCard), string.Empty);
    public static readonly BindableProperty AgeProperty =
        BindableProperty.Create(nameof(Age), typeof(string), typeof(PersonCard), string.Empty);


    public Person Person
    {
        get => (Person)GetValue(PersonProperty);
        set => SetValue(PersonProperty, value);
    }

    public string Name
    {
        get { return Person.Name; }
    }

    public string Age
    {
        get { return Person.Age.ToString(); }
    }

    async void OnTapped(object sender, EventArgs args)
    {
        Page page = new NavigationPage(new PersonFullView(Person));
        await Navigation.PushAsync(new NavigationPage(page));
        
    }
}

PersonFullView.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomViewListTest.Views.PersonFullView"
             xmlns:views ="clr-namespace:CustomViewListTest.Views">
    <StackLayout>
        <Label Text="This page shows a person's details"></Label>
        <Label x:Name="PersonName"></Label>
        <Label x:Name="PersonAge"></Label>
        <Label Text="End"></Label>


    </StackLayout>
</ContentPage>

PersonFullView.cs

[XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class PersonFullView : ContentPage
    {
        public PersonFullView()
        {
            InitializeComponent();
   
        }

        public Person Person;

        public PersonFullView(Person person)
        {
            Person = person;
            InitializeComponent();
            PersonName.Text = person.Name;
            PersonAge.Text = person.Age.ToString();
        }


       public static readonly BindableProperty NameProperty =
          BindableProperty.Create(nameof(Name), typeof(string), typeof(PersonFullView), "No name");
       public static readonly BindableProperty AgeProperty =
           BindableProperty.Create(nameof(Age), typeof(string), typeof(PersonFullView), "No age");


        public string Name
        {
            get { return Person.Name; }
        }

        public string Age
        {
            get { return Person.Age.ToString(); }
        }
    }

PersonList.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomViewListTest.Views.PersonList"
             xmlns:views ="clr-namespace:CustomViewListTest.Views">
    <StackLayout x:Name="personStack">
        <Label Text="List of People"></Label>
    </StackLayout>

</ContentPage>

PersonList.cs

[XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class PersonList : ContentPage
    {
        public PersonList()
        {
            InitializeComponent();
        }

        public List<Person> People;

        public List<PersonCard> cards { get; set; }
        public PersonList(List<Person> people)
        {
            InitializeComponent();
            People = people;
            cards = new List<PersonCard>();

            foreach (var p in people)
            {
                personStack.Children.Add(new PersonCard(p));
            }

            BindingContext = this;
        }


    }

The way it works is that in personList, it defines 2 Person objects, then uses the PersonCard constructor which takes a person object, to create the cards. I've used a stackLayout because I couldn't get the same functionality to work with a listview, which I would prefer. I think the problem stems from a list view not being able to hold contentviews, instead it holds lists of objects and you give it a bindable template. I couldn't get that working.

You may also notice I got the bindable properties working for PersonCard, but not for PersonFullView. I tried using basically identical code for the latter, but to no avail. I think something about the bindable properties on a page that doesn't exist at startup is fishy.

So, I'm curious how I would achieve this using Bindings, instead of create non-parameterless contructors for my views and pages, which I've not really seen in any examples. Also, I'm interested in moving as much logic to the xaml files. Obviously you can do it all from the cs file behind, but I find that very hard to get the layout right.

解决方案

Since you had used Data-Binding , it would be better to handle logic (fill data and navigation) in ViewModel and use Command instead of Click Event .

Also, I'm interested in moving as much logic to the xaml files

I couldn't get the same functionality to work with a listview, which I would prefer.

So you could modify and improve the code like following . I used ListView to display the data .

in PersonCard

using CustomViewListTest.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace CustomViewListTest.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class PersonCard : ContentView
    {

     
        public PersonCard()
        {
            InitializeComponent();
        }

        public static readonly BindableProperty NameProperty = 
            BindableProperty.Create(nameof(Name), typeof(string), typeof(PersonCard), string.Empty);
        public static readonly BindableProperty AgeProperty =
            BindableProperty.Create(nameof(Age), typeof(string), typeof(PersonCard), string.Empty);


       
        public string Name
        {
            get => (string)GetValue(NameProperty);
            set => SetValue(NameProperty, value);
        }

        public string Age
        {
            get => (string)GetValue(AgeProperty);
            set => SetValue(AgeProperty, value);
        }


        public static readonly BindableProperty ClickCommandProperty =
            BindableProperty.Create(nameof(ClickCommand), typeof(ICommand), typeof(PersonCard));

        public ICommand ClickCommand
        {
            get => (ICommand)GetValue(ClickCommandProperty);
            set => SetValue(ClickCommandProperty, value);
        }

        public static BindableProperty ClickParameterProperty =
            BindableProperty.Create(nameof(ClickParameter), typeof(object), typeof(PersonCard));

        public object ClickParameter
        {
            get => (object)GetValue(ClickParameterProperty);
            set => SetValue(ClickParameterProperty, value);
        }

    }
}

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomViewListTest.Views.PersonCard"
             xmlns:System="clr-namespace:System;assembly=mscorlib"
             x:Name="card"
             
             >

    <ContentView.Content>
        <Frame BorderColor="#3F3F3F" Padding="0" Margin="2">
            <Frame.GestureRecognizers>
                <TapGestureRecognizer Command="{Binding ClickCommand,Source={x:Reference card}}"  CommandParameter="{Binding ClickParameter,Source={x:Reference card}}"/>
            </Frame.GestureRecognizers>
            <StackLayout Orientation="Horizontal">
                <Label Text="{Binding Name,Source={x:Reference card}}" TextColor="Red"></Label>
                <Label Text="{Binding Age,Source={x:Reference card}}" TextColor="Green"></Label>
            </StackLayout>
        </Frame>
    </ContentView.Content>
</ContentView>

in PersonList

using CustomViewListTest.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using System.Windows.Input;

namespace CustomViewListTest.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class PersonList : ContentPage
    {
        public PersonList()
        {
            InitializeComponent();

            BindingContext = new MyViewModel(this.Navigation);
        }
   

    }



    public class MyViewModel
    {
        public ICommand ClickCommand { get; private set; }

        INavigation CurrentNavigation;

        public ObservableCollection<Person> MyItems {get;set;}

        public MyViewModel( INavigation navigation)
        {

            CurrentNavigation = navigation;

            MyItems = new ObservableCollection<Person>() { new Person("Jack",23),new Person("Lucas",25) };

            ClickCommand = new Command(async (org) =>
            {
                var item = org as Person;
                PersonFullView page = new PersonFullView(item);
                await CurrentNavigation.PushAsync(page);

            });

        }

    }
}

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="CustomViewListTest.Views.PersonList"
             xmlns:views ="clr-namespace:CustomViewListTest.Views"
             x:Name="page"
             >
    <StackLayout>

        <ListView ItemsSource="{Binding MyItems}">
                <ListView.ItemTemplate>
                  <DataTemplate>
                    <ViewCell>
                        <views:PersonCard Name="{Binding Name}" Age="{Binding Age}" ClickCommand="{Binding Path=BindingContext.ClickCommand,Source={x:Reference page}}" ClickParameter="{Binding .}" />
                    </ViewCell>
                </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>


    </StackLayout>

</ContentPage>

in App

MainPage = new NavigationPage(new PersonList());

这篇关于何时使用Xamarin绑定,而不是将对象传递给页面构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆