rest - Xamarin 使用 MVVM 将数据传递和检查到其他 View

标签 rest xamarin mvvm xamarin.forms

到目前为止,我可以将值传递给另一个 View ,但问题是我不知道如何使用 MVVM 来做到这一点。我尝试了文档和教程仍然没有运气。我怎样才能做到这一点?

我的项目流程:
- 用户将登录,当用户提供正确的信息时,它将返回一个 JSON 数组,其中包含用户的 ContactID。
- 这个 ContactID 现在被传递到另一个 View 。它将用于将服务器同步到本地数据库,反之亦然

我的问题是:
1. 如何使用 MVVM 将数据传递到其他 View ?
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 ();
        }
    }
}

最佳答案

如果您是 MVVM 新手,我强烈建议您使用 MVVM 辅助框架,例如 Prism。 , MVVMCrossMVVMLight (还有更多)。

我自己使用 Prism,我相信所有的框架在功能上都非常相似,在这里更多地归结为偏好。我将向您展示如何在基于 Prism 的应用程序中的 View 之间传递数据。在我们开始之前,值得下载 prism Visual Studio 扩展并使用模板包生成一个 prism 项目。我使用 DryIoc 容器。

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

您将首先设置您的 prism 项目,为 View A 和 B 创建一个 XAML 前置 View ,然后创建 2 个类文件并创建相关的 View 模型(我将向您展示如何)。

首先创建以下文件:

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

  • 在您的 app.cs 中注册 View 和 View 模型:
    //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>();
    }
    

    现在通过添加以下内容来格式化您的 View 模型:
    public class ViewAViewModel : ViewModelBase
    {
        INavigationService _navigationService;
    
        public ViewAViewModel(INavigationService navigationService) : base(navigationService)
        {
            Title = "ViewA";
    
            _navigationService = navigationService;
        }
    }
    

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

    现在在 View 中 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}"/>`
    

    现在我已经为你添加了绑定(bind),让我们来创建属性吧!

    在 View 模型 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
    }
    

    现在我们有一个可绑定(bind)属性和一个按钮按下命令,将以下内容添加到构造函数中:
    public ViewAViewModel(INavigationService navigationService) : base(navigationService)
    {
        Title = "ViewA";
    
        _navigationService = navigationService;
    
        _viewAText = string.Empty;
    
        OnNavigateCommand = new DelegateCommand(OnNavigate);
    }
    

    现在 View A 可以从入口控件绑定(bind)文本,并为命令提供事件处理程序!

    让我们跳到 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 中添加的标签已连接到 View 模型。现在让我们将文本从 A 中的条目传递到 B!

    返回 View A 将以下内容添加到 OnNavigate方法:
    private void OnNavigate()
    {
        NavigationParameters navParams = new NavigationParameters();
        navParams.Add("PassedValue", _viewAText);
        _navigationService.NavigateAsync("ViewB", navParams);
    }
    

    导航服务非常强大,允许您在 View 之间传递字典 (NavigationParameters)。在这段代码中,我们创建了一些 NavigationParameter ,将我们条目中文本的值添加到它们,然后询问navigationService (它处理来自 Prism 中 View 模型的所有导航)导航到 ViewB,将参数传递给它。

    在 View B 中,我们可以使用 Prism 提供的一些内置方法来监听这些参数。如果您键入 override在 ViewBViewModel 你会看到方法:
  • OnNavigatingTo
  • OnNavigatedTo
  • OnNavigatedFrom

  • 在这种情况下,我们要使用 OnNavigatingTo (在 View 之间的转换期间触发)。拉入该方法和以下内容:
    public override void OnNavigatingTo(NavigationParameters parameters)
    {
        base.OnNavigatingTo(parameters);
    
        if (parameters.ContainsKey("PassedValue"))
        {
            _textFromViewA = (string)parameters["PassedValue"];
    
            RaisePropertyChanged("TextFromViewA");
        }
    }
    

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

    下面是结果的gif!

    Gif of the results from this answer!

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

    有关棱镜如何工作的更多信息,我建议去 read the docswatch Brian Lagunas' appearance on the Xamarin Show!

    祝你好运!

    关于rest - Xamarin 使用 MVVM 将数据传递和检查到其他 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51549737/

    相关文章:

    android - 调试 native Android 崩溃的最佳方法?

    wpf - WPF- ItemsControl的ListView与TextBoxes性能问题

    java - 什么 Maven 依赖项将 Swagger 与 DropWizard 0.7.0 一起使用

    rest - 尝试登录 Keycloak Admin WS

    java - Jersey 远程 IP 地址无法正常工作

    rest - javax.ws.rs.core.Response 在 java1.6 中转换为字符串

    android - VS2017/Xamarin.Android : VS thinks it's still debugging after the emulator is closed

    ios - UIImagePickerController 显示最后单击的图像。我正在使用 Monotouch/Xamarin Studio

    c# - View 模型或XAML代码隐藏的WPF CollectionViewSource

    javascript - 将简单 View 模型与单个记录绑定(bind)