【问题标题】:Xamarin Passing and checking data to other view using MVVMXamarin 使用 MVVM 将数据传递和检查到其他视图
【发布时间】:2019-01-04 02:14:27
【问题描述】:

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

我的项目流程:
- 用户将登录,当用户提供正确的信息时,它将返回一个 JSON 数组,其中包含用户的 ContactID。
- 这个 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 ();
        }
    }
}

【问题讨论】:

标签: rest xamarin mvvm xamarin.forms


【解决方案1】:

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

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

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

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

首先创建以下文件:

  • 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(&lt;ContentPage.Content&gt;&lt;/ContentPage.Content&gt; 内:

<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 可以绑定来自入口控件的文本,并为命令提供事件处理程序!

让我们跳到视图 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");
    }
}

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

下面是结果的 gif 图像!

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

有关 prism 工作原理的更多信息,我建议前往 read the docswatch Brian Lagunas' appearance on the Xamarin Show!

祝你好运!

【讨论】:

  • 我可以获取数据,但是我想将其存储到一个变量中,以便获取特定用户的数据并将其存储到我的本地数据库中,我只是不知道在 MVVM 中执行此操作格式
  • 为您的数据库访问类创建一个接口,同时创建一个接口。在您的视图模型中获取接口并对其进行初始化(prism 使用 DI,以便通过 ctor 自动完成)。然后您的数据库层可以通过您的视图模型访问,并具有所有 MVVM 优势(它是抽象的,可以在测试中模拟)
  • 你能帮我开始使用代码吗?已经 5 天了,我仍然坚持这一点,请帮助
  • 请帮我解决这个问题 5 天了
  • 所以你想知道如何在 xamarin 中使用 sqlite 数据库,以及如何从视图模型中访问它?您应该先编辑问题以反映这一点,然后我会为您提供答案!
【解决方案2】:

我已经实现了相同的,希望这对你有帮助。

我已经创建了一个 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);
    }

您需要做的最后一件事是将您的视图与您的视图模型绑定

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

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

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

【讨论】:

  • 我觉得稍微懂一点mvvm就很容易理解了
  • 不幸的是,我是 MVVM 的新手
  • 关注此文档可能会对您有所帮助link
猜你喜欢
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2018-06-01
  • 1970-01-01
相关资源
最近更新 更多