如何在Xamarin PCL项目中进行数据绑定?

时间:2017-04-04 20:41:27

标签: xamarin mvvm data-binding

我想使用Xamarin在xaml中创建一个简单的登录UI。我在MainPage中使用Entry创建一个用户名和密码字段,然后我尝试将它们绑定到我的LoginViewModel,在那里我可以访问我的connexion方法。

当我在Mainpage代码后面定义Binding上下文时,应用程序只是关闭,我不明白为什么,我做错了什么?

MainPage.xaml中

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:suivAAndroid"
             x:Class="suivAAndroid.MainPage">

    <StackLayout
        VerticalOptions="CenterAndExpand">
        <Image></Image>
    <Label
        Text="Login"
        StyleId="lbl_login"></Label>
    <Entry
        StyleId="ent_login"
        Text="{Binding Username}"></Entry>
        <Label
            Text="Mot de passe"
            StyleId="ent_mdp"></Label>
        <Entry
            StyleId="ent_mdp"
            Text="{Binding Password}"></Entry>
        <Button 
            Clicked="connexion_click"
            Text="Connexion"></Button>
    </StackLayout>
</ContentPage>

MainPage.xaml.cs中

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace suivAAndroid
{

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();

            BindingContext = new LoginViewModel(); // Here is where it does not work. If the line is commented out, then the application launch without stopping but because there is no binding context I cant get the user inputs.
        }


        private void connexion_click(object sender, EventArgs e)
        {
            LoginViewModel connexionBtn = new LoginViewModel();
            Device.BeginInvokeOnMainThread(async () =>
                {
                    await connexionBtn.Connexion();
                });
        }
    }
}

LoginViewModel.cs

using suivAAndroid.Models;
using suivAAndroid.Views;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace suivAAndroid
{
    public class LoginViewModel
    {
        #region propriétés
        public string Username
        {
            get
            {
                return Username;
            }
            set
            {
                Username = value;
            }
        }

        public string Password
        {
            get
            {
                return Password;
            }
            set
            {
                Password = value;
            }
        }
        #endregion

        #region constructor
        public LoginViewModel()
        {

        }
        #endregion

        #region methodes

        public void CreerListeVisiteurDur(List<Visiteur> uneListe)
        {
            Visiteur unVisiteur = new Visiteur("Clooney", "George", "cgeorge", "azerty", "rue du port", "59", "lille", new DateTime(2015 / 07 / 13));
            uneListe.Add(unVisiteur);
        }
        public async Task Connexion()
        {
            List<Visiteur> uneListe = new List<Visiteur>();
            CreerListeVisiteurDur(uneListe);
            if (!string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password))
            {
                foreach (Visiteur unVisiteur in uneListe)
                {
                    string login = unVisiteur.login;
                    string pass = unVisiteur.mdp;

                    if (login == Username && pass == Password)
                    {
                        App.Current.MainPage = new CreerVisite();
                    }

                }
            }

        }
        #endregion
    }
}

2 个答案:

答案 0 :(得分:2)

您的ViewModel属性具有无限循环:

     $http.get('catalog/view/theme/default/template/confirm/fetch_product.php').then(function(response){ $scope.products = response.data.records; });
$scope.items = [];
var counter = 0;
$scope.loadMore = function($scope) {
    var last = $scope.products.length;
    for (var i = 0; i < 10; i++) {
        if(counter >= last) { break; }
         $scope.items.push($scope.products[counter]);
        counter += 1;
    }
};
$scope.loadMore();

致电 public string Username { get { return Username; } set { Username = value; } } 会致电Username = value上的setUsername会再次致电Username = value

此外,为了使ViewModel可绑定,您必须实现INotifyPropertyChanged

如果你想要一个易于使用的框架来帮助你做到这一点,我建议Mvvm Light

以下是ViewModel的示例:

public class MyViewModel : INotifyPropertyChanged
{
     public event EventHandler<PropertyChangedEventArgs> OnPropertyChanged;
     private string _username;
     public string Username
     {
         get
         {
             return _username;
         }
         set
         {
             _username = value;
             PropertyChanged?.Invoke(new PropertyChangedEventArgs("Username");
         }
     }
....
}

答案 1 :(得分:1)

  1. 在connexion_click中,您创建的VM副本与您为BindingContext创建的先前副本无关。

    公共部分类MainPage:ContentPage     {         私人LoginViewModel vm;

        public MainPage()
        {
            InitializeComponent();
    
            vm = new LoginViewModel();
            BindingContext = vm;
    
        }
    
    
        private void connexion_click(object sender, EventArgs e)
        {
    
            Device.BeginInvokeOnMainThread(async () =>
                {
                    await vm.Connexion();
                });
        }
    }
    
  2. 您的VM应实施INotifyPropertyChanged

  3. 您的VM有一个递归的getter