Xamarin MVVM passing data to other view - xamarin

I want to pass the data to another view page. So far I can get the data I need to pass. My problem is how do I pass the data in MVVM. I used Application.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true); When I add contactId inside DatabaseSyncPage() an error occurs. "The error is 'DatabaseSyncPage' does not contain a constructor that takes 1 arguments"
My code:
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 OnProperyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string username;
public string password;
public string Username
{
get { return username; }
set
{
username = value;
OnProperyChanged(nameof(Username));
}
}
public string Password
{
get { return password; }
set
{
password = value;
OnProperyChanged(nameof(Password));
}
}
public class LoggedInUser
{
public string 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 { myId = 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 int myId { get; set; }
public DatabaseSyncPage ()
{
InitializeComponent ();
DisplayAlert("Message", Convert.ToString(myId), "ok");
}
}
}

If you want to send the int. First declare that in your DatabaseSyncPage
Like below
public partial class DatabaseSyncPage : ContentPage
{
public DatabaseSyncPage( int Id)
{
}
}
& when you are pushing your page in your code else block do like this
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);
}

I'm assuming that contactID is an int.
Create an additional constructor in your DatabaseSyncPage:
public DatabaseSyncPage (int contactID)
{
// TODO: Do something with your id
}
But this passes the data to the page, not the page model.
Are you using any kind of framework? It would probably be worth looking into that.

You can use xamrin.plugins.settings nuget package.

Related

Asp.net-core api response WaitingForActivision

Can someone point me into the right direction what I am doing wrong in this Api call? I am getting an odd error that I don’t know what it means. The api call should work as I tested it using VBA and I get a response with the payload. Also any feedback is welcomed.
Id = 190, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" - this is the response I am getting back from it
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Xml.Linq;
namespace BarcodeScanner.Classes
{
public class Api : IDisposable
{
private readonly TimeSpan _timeout;
private HttpClient _httpClient;
private HttpClientHandler _httpClientHandler;
private readonly string _baseUrl;
private readonly string _credentials;
private const string MediaTypeXml = "application/xml";
public Api(string baseUrl, string authToken, TimeSpan? timeout = null)
{
_baseUrl = NormaliseBaseUrl(baseUrl);
_credentials = Base64Encode(authToken);
_timeout = timeout ?? TimeSpan.FromSeconds(90);
}
public async Task<string> GetAsync(string url)
{
EnsureHttpClientCreated();
using (var response = await _httpClient.GetAsync(url).ConfigureAwait(continueOnCapturedContext: false))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
public void Dispose()
{
_httpClientHandler?.Dispose();
_httpClient?.Dispose();
}
private void CreateHttpClient()
{
_httpClientHandler = new HttpClientHandler
{
AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip
};
_httpClient = new HttpClient(_httpClientHandler, false)
{
Timeout = _timeout
};
if (!string.IsNullOrWhiteSpace(_baseUrl))
{
_httpClient.BaseAddress = new Uri(_baseUrl);
}
_httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + _credentials);
}
private void EnsureHttpClientCreated()
{
if (_httpClient == null)
{
CreateHttpClient();
}
}
//call the api
try
{
using (var client = new Api(requestUrl, authToken))
{
var response = client.GetAsync(requestUrl);
}
}
catch (Exception err)
{
throw new Exception("Something went wrong: ", err);
}

How to setup my bindingcontext for my xamarin.forms app with mvvm and sqlite

The basic of my app is that i have an AgendaPage which has a collectionview of items and when i click the add icon, i can fill a form to populate this collectionview.
My app was working when i didn't set my app MVVM style but i am trying to apply the MVVM logic to my app.
Currently if i set the BindingContext of my NewFormPage to Agenda() my NewFormPage opens when i click the add button BUT if i set my BindingContext to NewFormViewModel, nothing open up and my app crash so i am trying to figure out what i am doing wrong in setting up this MVVM.
Note: currently i only have a clicked function to open up the page ( didn't implement the command yet, i was trying to implement the save command).
Agenda.cs in the database folder
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using SQLite;
using Calculette.Database;
namespace Calculette.Models
{
[Table("Agenda")]
public class Agenda
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Topic { get; set; }
public string Duration { get; set; }
public DateTime Date { get; set; }
}
}
NewFormViewModel.cs in the ViewModel folder
using Calculette.Database;
using Calculette.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
namespace Calculette.ViewModel
{
class NewFormViewModel : BaseViewModel
{
public Command AgendaSaveFormCommand { get; set; }
public NewFormViewModel()
{
AgendaSaveFormCommand = new Command(async () => await SaveForm(), () => !IsBusy);
}
public string Topic
{
get => Topic;
set
{
Topic = value;
NotifyPropertyChanged();
}
}
public string Duration
{
get => Duration;
set
{
Duration = value;
NotifyPropertyChanged();
}
}
public DateTime Date
{
get => Date;
set
{
Date = value;
NotifyPropertyChanged();
}
}
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set
{
isBusy = value;
//OnPropertyChanged();
AgendaSaveFormCommand.ChangeCanExecute();
}
}
public int ID { get; }
async Task SaveForm()
{
IsBusy = true;
await Task.Delay(4000);
IsBusy = false;
Agenda agenda = new Agenda();
await App.Database.SaveAgendaAsync(agenda);
await Application.Current.MainPage.DisplayAlert("Save", "La tâche a été enregistrée", "OK");
}
}
}
NewFormPage.xaml.cs in the Views folder
using Calculette.Models;
using Calculette.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Calculette.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NewFormPage : ContentPage
{
public NewFormPage ()
{
InitializeComponent ();
// BindingContext = new Agenda();
BindingContext = new NewFormViewModel();
}
}
}
AgendaPage.xaml in the views folder (xaml that calls Clicked that open NewFormPage
<ImageButton Source="iconplus.png" HeightRequest="30" WidthRequest="30" Clicked="GoToNewFormPage"></ImageButton>
the GoToNewFormPage function in AgendaPage.xaml.cs
protected async void GoToNewFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.NewFormPage());
}
You did not set value for the object's property when clicking on the add icon.
async Task SaveForm()
{
IsBusy = true;
await Task.Delay(4000);
IsBusy = false;
Agenda agenda = new Agenda();
//here you should set value of a blank object
Agenda.Topic = xx;
Agenda.Date = xx;
Agenda.Duration = xx;
await App.Database.SaveAgendaAsync(agenda);
await Application.Current.MainPage.DisplayAlert("Save", "La tâche a été enregistrée", "OK");
}
all of your properties are implemented incorrectly
this will lead to an infinite recursive loop - Duration will call Duration will call Duration... until your app crashes
public string Duration
{
// this will just call the capital-D Duration property again
// which will then call itself again, and again, and again
get => Duration;
set
{
// this will call the setter for the capital-D Duration property recursively
Duration = value;
NotifyPropertyChanged();
}
}
you need to have a private backing field that is named differently than the property
private string duration;
public string Duration
{
get => duration;
set
{
duration = value;
NotifyPropertyChanged();
}
}

Xamarin, why can't my if/else statement, retrieving data from Settings.plugin

LastPickName is not empty but it kept picking the else statement... maybe I'm putting it in the wrong area?
I have a label text to output what's in LastPickName just to make sure it's not empty or empty.
using Plugin.Settings;
using Plugin.Settings.Abstractions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace App424
{
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
private static ISettings AppSettings => CrossSettings.Current;
public static string LastPickValue
{
get => AppSettings.GetValueOrDefault(nameof(LastPickValue), string.Empty);
set => AppSettings.AddOrUpdateValue(nameof(LastPickValue), value);
}
public static string LastPickName
{
get => AppSettings.GetValueOrDefault(nameof(LastPickName), string.Empty);
set => AppSettings.AddOrUpdateValue(nameof(LastPickName), value);
}
public object LastPickname { get; private set; }
public MainPage()
{
InitializeComponent();
List<string> list = new List<string>();
list.Add("Right1");
list.Add("Right2");
list.Add("Right3");
list.Add("Right4");
//populate picker selection
drainlocationPicker1.ItemsSource = list;
//Set the default value
drainlocationPicker1.SelectedItem = LastPickValue;
nameEntry.Placeholder = LastPickName;
//names.Text = LastPickName;
nameLabel.Text = LastPickName;
if (LastPickName == null)
{
settingsButton.IsVisible = true;
nextButton.IsVisible = false;
}
else
{
nextButton.IsVisible = true;
settingsButton.IsVisible = false;
}
void Handle_Unfocused(object sender, Xamarin.Forms.FocusEventArgs e)
{
LastPickName = nameEntry.Text;
}
private void DrainlocationPicker1_SelectedIndexChanged(object sender, EventArgs e)
{
string nlocation1 = (string)drainlocationPicker1.SelectedItem;
LastPickValue = nlocation1;
}
}
}
}
LastPickName is empty it should show settingsButton if not show nextButton.
LastPickName is empty why is it not showing settingsButton?
if (LastPickName == "")
i thought null is empty but as Sami commented it's not.

c# - selenium Nunit testing - how to do validation check for signup form

Hi I am trying to test this online signup form. I have created a test but I would like to do a validation check on each field,
e.g.
For Name field
driver.FindElement(By.Id("Name")).SendKeys("Clayton")
I would like to try different text/number/characters and see what goes through and what fails.
Is there any way i could do this?
please see the codes.
using System;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using NUnit.Framework;
using OpenQA.Selenium;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Support.UI;
namespace SeleniumTests
{
[TestFixture]
public class loop
{
private IWebDriver driver;
private StringBuilder verificationErrors;
private string baseURL;
private bool acceptNextAlert = true;
[SetUp]
public void SetupTest()
{
driver = new FirefoxDriver();
baseURL = "http://something.com/";
verificationErrors = new StringBuilder();
}
[TearDown]
public void TeardownTest()
{
try
{
driver.Quit();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
Assert.AreEqual("", verificationErrors.ToString());
}
[Test]
public void TheSignupTest()
{
driver.Navigate().GoToUrl(baseURL + "/Account/Login?ReturnUrl=%2f");
driver.FindElement(By.Id("UserName")).Clear();
driver.FindElement(By.Id("UserName")).SendKeys("something");
driver.FindElement(By.Id("Password")).Clear();
driver.FindElement(By.Id("Password")).SendKeys("something");
driver.FindElement(By.CssSelector("input.btn.small")).Click();
driver.FindElement(By.Id("nav2")).Click();
driver.FindElement(By.Id("upload-file")).Click();
driver.FindElement(By.Id("Name")).Clear();
driver.FindElement(By.Id("Name")).SendKeys("00");
driver.FindElement(By.Id("ReferenceNumberPrefix")).Clear();
driver.FindElement(By.Id("ReferenceNumberPrefix")).SendKeys("00");
driver.FindElement(By.Name("submit")).Click();
}
private bool IsElementPresent(By by)
{
try
{
driver.FindElement(by);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
private bool IsAlertPresent()
{
try
{
driver.SwitchTo().Alert();
return true;
}
catch (NoAlertPresentException)
{
return false;
}
}
private string CloseAlertAndGetItsText()
{
try
{
IAlert alert = driver.SwitchTo().Alert();
string alertText = alert.Text;
if (acceptNextAlert)
{
alert.Accept();
}
else
{
alert.Dismiss();
}
return alertText;
}
finally
{
acceptNextAlert = true;
}
}
}
}
I think a good start would be to transform your test into a parameterized test and use the TestCaseAttribute.
Your test could then look like this:
[Test]
[TestCase("Clayton", "abc", true)]
[TestCase("Clayton", "def", false)]
public void TheSignupTest(string username, string password, bool isAccepted)
{
driver.Navigate().GoToUrl(baseURL + "/Account/Login?ReturnUrl=%2f");
driver.FindElement(By.Id("UserName")).Clear();
driver.FindElement(By.Id("UserName")).SendKeys(username);
driver.FindElement(By.Id("Password")).Clear();
driver.FindElement(By.Id("Password")).SendKeys(password);
driver.FindElement(By.CssSelector("input.btn.small")).Click();
driver.FindElement(By.Id("nav2")).Click();
driver.FindElement(By.Id("upload-file")).Click();
driver.FindElement(By.Id("Name")).Clear();
driver.FindElement(By.Id("Name")).SendKeys("00");
driver.FindElement(By.Id("ReferenceNumberPrefix")).Clear();
driver.FindElement(By.Id("ReferenceNumberPrefix")).SendKeys("00");
driver.FindElement(By.Name("submit")).Click();
if (isAccepted)
{
Assert.That(driver.Url, Is.EqualTo(baseURL + "/PageWhereClientIsRedirectedToAfterSuccessfulLogin"));
}
else
{
Assert.That(driver.FindElement(By.Name("ErrorBox")).Text, Is.EqualTo("Login failed"));
}
}
The test cases are defined using the TestCaseAttribute:
[TestCase("Clayton", "abc", true)]
[TestCase("Clayton", "def", false)]
So you have two test cases in your test runner.

Can SolrNet client run at a different machine from solr server?

I set up a solr server running in Tomcat in machine 192.168.0.113(Centos 5.5).
And I deploy a website in matchine 192.168.0.114(Windows server 2003).
I use solrnet in matchine 192.168.0.114.
The full code like bellow(which have been edited thanks to #Paige Cook):
using System;
using System.Collections.Generic;
using System.Text;
using SolrNet;
using NUnit.Framework;
using SolrNet.Attributes;
using SolrNet.Commands.Parameters;
using Microsoft.Practices.ServiceLocation;
namespace MySolrNet
{
public class Video
{
private string videoid;
[SolrField("videoid")]
public string Videoid
{
get { return videoid; }
set { videoid = value; }
}
private string videoname;
[SolrField("videoname")]
public string Videoname
{
get { return videoname; }
set { videoname = value; }
}
private string videoorigin;
[SolrField("videoorigin")]
public string Videoorigin
{
get { return videoorigin; }
set { videoorigin = value; }
}
public Video(string id, string name, string origin)
{
this.Videoid = id;
this.Videoname = name;
this.Videoorigin = origin;
}
public Video()
{
}
public void FixtureSetup()
{
Startup.Init<Video>("http://192.168.0.113:8070/solr");
}
public void Add()
{
Video p = new Video("1", "test video", "Solr Test");
ISolrOperations<Video> solr = ServiceLocator.Current.GetInstance<ISolrOperations<Video>>();
solr.Add(p);
solr.Commit();
}
}
[TestFixture]
public class VideoTests
{
[TestFixtureSetUp]
public void FixtureSetup()
{
Startup.Init<Video>("http://192.168.0.113:8070/solr");
}
[Test]
public void Add()
{
Video p = new Video("1", "test video", "Solr Test");
ISolrOperations<Video> solr = ServiceLocator.Current.GetInstance<ISolrOperations<Video>>();
solr.Add(p);
solr.Commit();
}
[Test]
public void Query()
{
ISolrOperations<Video> solr = ServiceLocator.Current.GetInstance<ISolrOperations<Video>>();
SolrQueryResults<Video> results = solr.Query(new SolrQueryByField("videoid", "33013"));
Assert.AreEqual(1, results.Count);
Console.WriteLine(results[0].Videoname);
}
}
}
However,both Add and Query test fail.
It complains: TestFixture failed: SetUp : System.IO.FileLoadException : Could not load file or assembly“SolrNet, Version=0.4.0.2002, Culture=neutral, PublicKeyToken=bc21753e8aa334cb” Or one of its dependencies.
But I have add reference to Microsoft.Practices.ServiceLocation.dll and SolrNet.dll in my projoect,is there any other dll files I just miss?
By the way,,I can access my solr sever in browser with this url:http://192.168.0.113:8070/solr.
Can anyone tell me:
Can I run solrnet and solr in different machines?
How to do it.
Thanks a lot!
I don't understand why you're using two different URLs when you Init Solr. Try changing the URL in Paige's application to the one you posted in your original question: http://192.168.0.113:8070/solr
Thanks for posting the code. The first thing I see is that you are using the test class as the class type to pass data to Solr. Split those out, that might be causing some issues. I would suggest the following:
public class Video
{
private string videoid;
[SolrField("videoid")]
public string Videoid
{
get { return videoid; }
set { videoid = value; }
}
private string videoname;
[SolrField("videoname")]
public string Videoname
{
get { return videoname; }
set { videoname = value; }
}
private string videoorigin;
[SolrField("videoorigin")]
public string Videoorigin
{
get { return videoorigin; }
set { videoorigin = value; }
}
}
[TestFixture]
public class VideoTests
{
[TestFixtureSetUp]
public void FixtureSetup()
{
Startup.Init<Video>("http://192.168.0.113/solr");
}
[Test]
public void Add() {
Video p = new Video("1","test video","Solr Test");
ISolrOperations<Video> solr = ServiceLocator.Current.GetInstance<ISolrOperations<Video>>();
solr.Add(p);
solr.Commit();
}
[Test]
public void Query()
{
ISolrOperations<Video> solr = ServiceLocator.Current.GetInstance<ISolrOperations<Video>>();
SolrQueryResults<Video> results = solr.Query(new SolrQueryByField("videoid", "33013"));
Assert.AreEqual(1, results.Count);
Console.WriteLine(results[0].Videoname);
}
}
Update:
Try this in a console application and see if it works...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SolrNet;
using Microsoft.Practices.ServiceLocation;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
Startup.Init<Video>("http://192.168.0.113:8070/solr");
var solr = ServiceLocator.Current.GetInstance<ISolrOperations<Video>>();
var video = new Video("1", "test", "test");
solr.Add(video);
solr.Commit();
var results = solr.Query(SolrQuery.All);
Console.WriteLine("{0} - {1} - {2}",
results[0].Videoid, results[0].Videoname, results[0].Videoorigin);
}
}
public class Video
{
public Video(string id, string name, string origin)
{
Videoid = id;
Videoname = name;
Videoorigin = origin;
}
public string Videoid { get; set;
public string Videoname { get; set; }
public string Videoorigin { get; set; }
}
}
Can you check your project setup as suggested by Paige?
Do you have SolrNet source code added as project reference in your solution?
If you are using the dll, can you paste your .csproj file contents? If it is urgent, download the source code and add as project reference in your solution until you figure out the issue.

Resources