Xamarin使用MVVM将数据传递并检查到其他视图

时间:2018-07-27 01:54:30

标签: rest xamarin mvvm xamarin.forms

到目前为止,我可以将值传递给另一个视图,但是问题是我不知道如何使用MVVM来执行此操作。我尝试过文档和教程仍然没有运气。我该如何实现?

我的项目流程:
-用户将登录,当用户提供正确的密码时,它将返回一个包含用户的ContactID的JSON数组。
-现在,此ContactID可以传递到另一个视图。它将用于将服务器同步到本地数据库,反之亦然

我的问题是:
1。如何使用MVVM将数据传递到其他视图?
2.如何检查数据是否正确传递?

HTTPWebRequest的输出:

  

[{“ ContactID”:“ 1”}]

我的代码:

LoginPageViewModel.cs

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Input;
using TBSMobileApplication.Data;
using TBSMobileApplication.View;
using Xamarin.Essentials;
using Xamarin.Forms;

namespace TBSMobileApplication.ViewModel
{
    public class LoginPageViewModel : INotifyPropertyChanged
    {
        void OnPropertyChanged(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        public string username;
        public string password;

        public string Username
        {
            get { return username; }
            set
            {
                username = value;
                OnPropertyChanged(nameof(Username));
            }
        }

        public string Password
        {
            get { return password; }
            set
            {
                password = value;
                OnPropertyChanged(nameof(Password));
            }
        }

        public class LoggedInUser
        {
            public int ContactID { get; set; }
        }

        public ICommand LoginCommand { get; set; }

        public LoginPageViewModel()
        {
            LoginCommand = new Command(OnLogin);
        }

        public void OnLogin()
        {
            if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
            {
                MessagingCenter.Send(this, "Login Alert", Username);
            }
            else
            {
                var current = Connectivity.NetworkAccess;

                if (current == NetworkAccess.Internet)
                {
                    var link = "http://192.168.1.25:7777/TBS/test.php?User=" + Username + "&Password=" + Password;
                    var request = HttpWebRequest.Create(string.Format(@link));
                    request.ContentType = "application/json";
                    request.Method = "GET";

                    using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                    {
                        if (response.StatusCode != HttpStatusCode.OK)
                        {
                            Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
                        }
                        else
                        {
                            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                            {
                                var content = reader.ReadToEnd();

                                if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
                                {
                                    MessagingCenter.Send(this, "Http", Username);
                                }
                                else
                                {
                                    var result = JsonConvert.DeserializeObject<List<LoggedInUser>>(content);
                                    var contactId = result[0].ContactID;
                                    Application.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(contactId), true);
                                }

                            }
                        }
                    }
                }
                else
                {
                    MessagingCenter.Send(this, "Not Connected", Username);
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
}

DatabaseSyncPage.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 TBSMobileApplication.View
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class DatabaseSyncPage : ContentPage
    {
        public DatabaseSyncPage (int contanctId)
        {
            InitializeComponent ();
        }
    }
}

2 个答案:

答案 0 :(得分:2)

如果您不熟悉MVVM,我强烈建议您使用MVVM帮助程序框架,例如PrismMVVMCrossMVVMLight(还有更多)。

我本人使用Prism,我相信所有框架在功能上都非常相似,在这里它更倾向于偏好。我将向您展示如何在基于Prism的应用程序中的视图之间传递数据。在我们开始之前,值得下载棱镜Visual Studio扩展并使用模板包来生成一个棱镜项目。我使用DryIoc容器。

想象一下我们有ViewA(带有ViewAViewModel)和ViewB(带有ViewBViewModel)的场景。在视图A中,我们有一个条目和一个按钮,当按下按钮时,ViewA中条目的文本将传递到ViewB,并在标签中显示。

您将首先设置您的棱镜项目,为View A和B创建一个XAML前端视图,然后创建2个类文件并创建相关的View模型(我将向您展示方法)。

首先创建以下文件:

  • ViewA(Xaml内容页面)
  • ViewB(Xaml内容页面)
  • ViewAViewModel(空类)
  • ViewBViewModel(空类)

在您的app.cs中注册视图和视图模型:

//You must register these views with prism otherwise your app will crash!
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<NavigationPage>();
    containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>();
    containerRegistry.RegisterForNavigation<ViewB, ViewBViewModel>();
}

现在通过添加以下内容来格式化视图模型:

public class ViewAViewModel : ViewModelBase
{
    INavigationService _navigationService;

    public ViewAViewModel(INavigationService navigationService) : base(navigationService)
    {
        Title = "ViewA";

        _navigationService = navigationService;
    }
}

还对ViewBViewModel重复上述步骤(更改相关名称)。

现在,在视图xaml中可以添加一些内容!将以下内容添加到ViewA.xaml(在<ContentPage.Content></ContentPage.Content>内部:

<StackLayout>
    <Entry Placeholder="Type Here..." Text="{Binding ViewAText}"/>
    <Button Text="Navigate" Command="{Binding OnNavigateCommand}"/>
</StackLayout>

以及在ViewB.xaml中:

`<Label Text="{Binding TextFromViewA}"/>`

现在我已经为您添加了绑定,所以让我们创建属性吧!

在视图模型A中添加:

private string _viewAText;
public string ViewAText
{
    get { return _viewAText; }
    set { SetProperty(ref _viewAText, value); }
}

public DelegateCommand OnNavigateCommand { get; set; }

private void OnNavigate()
{
    //Do Something
}

现在我们有了一个可绑定的属性和一个用于按下按钮的命令,将以下内容添加到构造函数中:

public ViewAViewModel(INavigationService navigationService) : base(navigationService)
{
    Title = "ViewA";

    _navigationService = navigationService;

    _viewAText = string.Empty;

    OnNavigateCommand = new DelegateCommand(OnNavigate);
}

现在视图A可以绑定进入控件中的文本,并具有命令的事件处理程序!

让我们跳进View B并将其连接起来!

添加属性:

private string _textFromViewA;
public string TextFromViewA
{
    get { return _textFromViewA; }
    set { SetProperty(ref _textFromViewA, value); }
}

并在构造函数中:

public ViewBViewModel(INavigationService navigationService) : base(navigationService)
{
    Title = "ViewB";

    TextFromViewA = string.Empty;
}

现在,我们在ViewB中添加的标签已连接到视图模型。现在,将文本从A条目传递到B!

返回视图A,将以下内容添加到OnNavigate方法中:

private void OnNavigate()
{
    NavigationParameters navParams = new NavigationParameters();
    navParams.Add("PassedValue", _viewAText);
    _navigationService.NavigateAsync("ViewB", navParams);
}

导航服务功能强大,可让您在视图之间传递字典(NavigationParameters)。在此代码中,我们创建了一些NavigationParameter,并在其中添加了文本值,然后要求navigationService(处理Prism中从视图模型进行的所有导航)导航至ViewB,并传递参数。

在视图B中,我们可以使用Prism提供的一些内置方法来监听这些参数。如果您在ViewBViewModel中键入override,则会看到以下方法:

  • OnNavigatingTo
  • OnNavigatedTo
  • OnNavigatedFrom

在这种情况下,我们要使用OnNavigatingTo(在视图之间的过渡期间触发)。拉入该方法并执行以下操作:

public override void OnNavigatingTo(NavigationParameters parameters)
{
    base.OnNavigatingTo(parameters);

    if (parameters.ContainsKey("PassedValue"))
    {
        _textFromViewA = (string)parameters["PassedValue"];

        RaisePropertyChanged("TextFromViewA");
    }
}

在这里,我们检查参数是否包含我们添加的值(通过搜索字典键),然后检索该值(由于字典为,因此将其广播到字符串中)。然后,将标签绑定到=的属性设置为传递的值,然后使用棱镜方法RaisePropertyChanged()引发属性更改事件,以便标签的绑定值更新!

下面是结果的gif!

Gif of the results from this answer!

这可能很多。我建议您尽快开始使用MVVM框架,它们确实非常易于使用,并且我认为它们对于制作可测试的,解耦的MVVM xamarin应用程序至关重要!

有关棱镜的工作原理的更多信息,建议您使用read the docswatch Brian Lagunas' appearance on the Xamarin Show!

祝你好运!

答案 1 :(得分:0)

我已经实施了相同的方法,希望对您有所帮助。

我已经创建了一个loginViewModel

  public class LoginVerificationVM : BaseViewModel // INotifyPropertyChanged
{
   private INavigation _navigation;
   private string usermobileno;
   public string UserMobileNo     
 { get { return usermobileno; }set  { usermobileno = value;
           OnPropertyChanged("UserMobileNo");     }

   }

 public LoginVerificationVM(INavigation navigation, string mobileno)
    {
        UserMobileNo = mobileno;
        _navigation = navigation;
    }

 public Command Login
    {
        get
        {
            return new Command(async () =>
            {
                bool status = await WebApi.CheckNetWorkStatus();
                if (status == false)
                {
                    MessageClass.messagesWindow("Check Ur Connectivity");
                    this.Isvisible = false;

                    return;
                }
                Isvisible = true;
                UserAuth ud = new UserAuth();
                ud.username = UserMobileNo;  // UserMobileNo;
                ud.password = Password;     // Password
                ud.grant_type = "password";  //GrantType
                Isvisible = true;
                //  IsBusy = false;
                    await Task.Delay(100);
                var json = Task.Run(() => WebApi.GetUserAuth(ud)).Result;
                //  IsBusy = false;
                if (json.ErrorMessage == "true")
                {
                    Application.Current.MainPage = new MasterPages.MasterPage(json.access_token);  //or use   _navigation.PushAsync(new ForgotPasswordOTP(UserMobileNo));
                }
                else
                {
                    MessageClass.messagesWindow(json.ErrorMessage);
                }
                Isvisible = false;
            });
        }
    }

}

Xaml代码

   <Entry x:Name="PasswordEntry" Grid.Row="2" IsPassword="True" Placeholder="******" HorizontalTextAlignment="Center" FontAttributes="Bold" TextColor="Black"  WidthRequest="150" HeightRequest="35" FontSize="13" Text="{Binding Password, Mode=TwoWay}" >

 <Button x:Name="Login" Grid.Row="3" HorizontalOptions="Center" BorderRadius="8"  Text="Login" WidthRequest="100" BackgroundColor="#f7941d" TextColor="White" Command="{Binding Login}" IsEnabled="{Binding Active,Mode=TwoWay}">

这是获取导航页面视图模型数据的实现方式

  public ForgotPasswordOTP(string Ph)
    {
        InitializeComponent();

        BindingContext = new ForgotPasswordOTPViewModel(this.Navigation,Ph);
    }

最后要做的就是将视图与viewmodel绑定

** BindingContext = new LoginVerificationVM(this.Navigation);**

最后一个问题的答案是您需要在C#中反序列化json 可以通过以下方式完成

   var userData = JsonConvert.DeserializeObject<YourObject>(result);