Xamarin C# - INotifyPropertyChanged Model - Error in JSON Deserialization - c#

I have a c# User model which is synced with the Azure Mobile services.
The definition of the User class is as follows:
public class Users : INotifyPropertyChanged
{
[JsonProperty("Id")]
private string id;
[JsonIgnore]
public string Id
{
get { return id; }
set { id = value; OnPropertyChanged("Id"); }
}
[JsonProperty("Name")]
private string name;
[JsonIgnore]
public string Name
{
get { return name; }
set { name = value; OnPropertyChanged("Name"); }
}
[JsonProperty("Email")]
private string email;
[JsonIgnore]
public string Email
{
get { return email; }
set { email = value; OnPropertyChanged("Email"); }
}
[JsonProperty("Password")]
private string password;
[JsonIgnore]
public string Password
{
get { return password; }
set { password = value; OnPropertyChanged("Password"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if(propertyName != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
Now, in the XAML page code, once the user logs in, I try to get the user, like so:
var user = (await App.MobileService.GetTable<Users>().Where(u => u.Email == this.txtEmail.Text).ToListAsync()).FirstOrDefault();
If I remove the JsonProperty() and JsonIgnore() on private and public members, I get the error: NewtonSoft.Json Deserialization error.
In the above code, is there any simpler way other than declaring JsonProperty() and JsonIgnore on each private and public fields respectively?

Related

How to get JSON from api in listview labels in Xamarin C#

I have the following code that retrieves json from an api. This works because when I put a breakpoint on it, it neatly shows the json from the url.
The json looks like this when I put a breakpoint on it
And the code of getting the json from the url looks like this
public static List GetAllSpecTypes(string acces_Token, string domain, out bool result)
{
result = true;
var specTypes = new List<Specification>();
if (!string.IsNullOrEmpty(domain))
{
try
{
using (HttpClient client = new HttpClient())
{
string url = $"{domain}/api/specification/GetSpecificationType";
client.BaseAddress = new Uri(url);
MediaTypeWithQualityHeaderValue contentType = new MediaTypeWithQualityHeaderValue("application/json");
client.DefaultRequestHeaders.Accept.Add(contentType);
client.DefaultRequestHeaders.Add("cache-control", "no-cache");
client.DefaultRequestHeaders.Add("Authorization", acces_Token);
HttpResponseMessage response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
string json = response.Content.ReadAsStringAsync().Result;
specTypes = JsonSerializer.Deserialize<List<Specification>>(json);
}
else
{
result = false;
}
}
}
catch (Exception)
{
//log!
}
}
return specTypes;
}
And the json from the breakpoint is this:
"[{\"SpecificationTypeId\":1,\"SpecificationTypeName\":\"Overig\"},{\"SpecificationTypeId\":2,\"SpecificationTypeName\":\"Eten/Drinken\"},{\"SpecificationTypeId\":3,\"SpecificationTypeName\":\"Parkeren\"},{\"SpecificationTypeId\":4,\"SpecificationTypeName\":\"Ander vervoer\"},{\"SpecificationTypeId\":5,\"SpecificationTypeName\":\"Materiaal\"},{\"SpecificationTypeId\":6,\"SpecificationTypeName\":\"Persoonlijke uitgaven\"},{\"SpecificationTypeId\":7,\"SpecificationTypeName\":\"Uitgaven cliƫnt\"},{\"SpecificationTypeId\":8,\"SpecificationTypeName\":\"Overnachting\"},{\"SpecificationTypeId\":9,\"SpecificationTypeName\":\"Congres / beursbezoek\"},{\"SpecificationTypeId\":10,\"SpecificationTypeName\":\"Brandstof\"},{\"SpecificationTypeId\":11,\"SpecificationTypeName\":\"Auto kosten\"},{\"SpecificationTypeId\":12,\"SpecificationTypeName\":\"Eigen vervoer\"},{\"SpecificationTypeId\":14,\"SpecificationTypeName\":\"Vervoer\"}]"
This method should return the specTypes to a viewmodel. But when I do, it's empty when I put a breakpoint on it.
That code is as follows
public ViewModel()
{
this.Source = new List<SourceItem>();
var data = Api.GetAllSpecTypes(Settings.AccessToken, Settings.Domain, out var valid);
foreach (var item in data)
{
Source.Add(new SourceItem(item.SpecificationName, item.SpecificationId));
}
}
What I want to achieve is that here that json is returned from the api call so that I can bind it to a label in a listview.
The listview xaml looks like this in which I put in the label where I use the following:
<Label
FontSize="18"
LineBreakMode="NoWrap"
Text="{Binding Name}"
TextColor="#474747"
VerticalOptions="FillAndExpand" />
What should be in the label are the specificationnames coming from the json
How can i achieve this?
This is my entire viewmodel according to my question
public class SourceItem : INotifyPropertyChanged
{
public SourceItem(string name, int id)
{
this.Name = name;
this.Id = id;
}
private string name;
public string Name
{
get { return this.name; }
set
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
private int id;
public int Id
{
get { return this.id; }
set
{
this.id = value;
this.OnPropertyChanged("Id");
}
}
private bool isSelected;
public bool IsSelected
{
get { return this.isSelected; }
set
{
this.isSelected = value;
this.OnPropertyChanged("IsSelected");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
public class ViewModel : INotifyPropertyChanged
{
private bool _isSelected = false;
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected != value)
{
_isSelected = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string name = null)
{
if (PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(name));
}
public ViewModel()
{
this.Source = new List<SourceItem>();
var data = Api.GetAllSpecTypes(Settings.AccessToken, Settings.Domain, out var valid);
foreach (var item in data)
{
Source.Add(new SourceItem(item.SpecificationName, item.SpecificationId));
}
}
public List<SourceItem> Source { get; set; }
}
And the Specification Class for the JSON is the following:
public class Specification
{
public int SpecificationId { get; set; }
public string SpecificationName { get; set; }
public string SpecificationDescription { get; set; }
}
How do I get the specification names from the json in the xaml label based on my question?
thanks in advance
your json looks like
"[{\"SpecificationTypeId\":1,\"SpecificationTypeName\"
while your C# classes do not include the "Type" in the name
public class Specification
{
public int SpecificationId { get; set; }
public string SpecificationName { get; set; }
public string SpecificationDescription { get; set; }
}
you either need to rename your C# properties to match the json, or use an attribute to map the name
[JsonProperty("SpecificationTypeId")]
public int SpecificationId { get; set; }

Sharing Data contract class among different services

I have this data contract class as a separate dll in my WCF server code:
namespace Engine.V100.SharedDataContract
{
#region Authorization
[DataContract(Namespace = "Engine.V100.SharedDataContract")]
[Serializable]
public class Identity
{
[DataMember]
public string UserName;
[DataMember]
public Guid UserID;
[DataMember]
public string PassWord;
[DataMember]
public Guid GroupCode;
}
#endregion
}
I referenced the same dll in client side code and I selected the option of "Reuse types in all referenced assemblies." But type Identity is still defined by each service reference separately and I have problem of conflicting assemblies.
This is the sample of what client side service reference generates:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Identity", Namespace="http://tempuri.org/")]
[System.SerializableAttribute()]
public partial class Identity : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string UserNameField;
private System.Guid UserIDField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string PassWordField;
private System.Guid GroupCodeField;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public string UserName {
get {
return this.UserNameField;
}
set {
if ((object.ReferenceEquals(this.UserNameField, value) != true)) {
this.UserNameField = value;
this.RaisePropertyChanged("UserName");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true, Order=1)]
public System.Guid UserID {
get {
return this.UserIDField;
}
set {
if ((this.UserIDField.Equals(value) != true)) {
this.UserIDField = value;
this.RaisePropertyChanged("UserID");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false, Order=2)]
public string PassWord {
get {
return this.PassWordField;
}
set {
if ((object.ReferenceEquals(this.PassWordField, value) != true)) {
this.PassWordField = value;
this.RaisePropertyChanged("PassWord");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true, Order=3)]
public System.Guid GroupCode {
get {
return this.GroupCodeField;
}
set {
if ((this.GroupCodeField.Equals(value) != true)) {
this.GroupCodeField = value;
this.RaisePropertyChanged("GroupCode");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
It may be considerable that referened type namespace is tempuri.
Please help

MVVM: Raise PropertyChanged event for a DataContract class members

I want to raise PropertyChanged event for a model with DataContract.
Initially I did this
[DataContract]
public partial class User : INotifyPropertyChanged
{
[DataMember(Name="username")]
public string Username
{
get
{
return this.Username;
}
set
{
this.Username = value;
RaisePropertyChanged("Username");
}
}
}
which gave StackOverflow Exception beacause of Infinite Recursion.
So the solution I come up with is
[DataContract]
public partial class User : INotifyPropertyChanged
{
private string _Username { get; set; }
[DataMember(Name="username")]
public string Username
{
get
{
return this._Username;
}
set
{
this._Username = value;
RaisePropertyChanged("Username");
}
}
}
Although this reflects the Username value to the control binding to "Username", this doesn't look the best way to me. Something is wrong. Also my model has approx 30-40 fields. Is this the right approach or can someone please suggest me a better way.
Thanks
I'd be so tempted to use caller-member-name here (if it is in your target framework):
private string _username;
[DataMember(Name="username")]
public string Username
{
get { return _username; }
set { SetField(ref _username, value); }
}
private void SetField<T>(ref T field, T value,
[CallerMemberName] string memberName = null)
{
if(!EqualityComparer<T>.Default.Equals(field,value))
{
field = value;
RaisePropertyChanged(memberName);
}
}
If caller-member-name isn't supported:
[DataMember(Name="username")]
public string Username
{
get { return this._Username; }
set { SetField(ref _Username, value, "Username"); }
}
[DataContract]
public partial class User : INotifyPropertyChanged
{
private string _Username;
[DataMember(Name="username")]
public string Username
{
get
{
return this._Username;
}
set
{
if(this._Username != value)
{
this._Username = value;
RaisePropertyChanged("Username");
}
}
}
}

Update in sql Ce in window phone 7

In project i user SQL CE, i have Table:
[Table]
public class Article : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define _cid: private field, public property, and database column.
private int _aid;
[Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
public int aid
{
get { return _aid; }
set
{
NotifyPropertyChanging("aid");
_aid = value;
NotifyPropertyChanged("aid");
}
}
// Define nameColor name: private field, public property, and database column.
private int _rid;
[Column]
public int rid
{
get { return _rid; }
set
{
NotifyPropertyChanging("rid");
_rid = value;
NotifyPropertyChanged("rid");
}
}
private string _title;
[Column]
public string title
{
get { return _title; }
set
{
NotifyPropertyChanging("title");
_title = value;
NotifyPropertyChanged("title");
}
}
private string _thumnail;
[Column]
public string thumnail
{
get { return _thumnail; }
set
{
NotifyPropertyChanging("thumnail");
_thumnail = value;
NotifyPropertyChanged("thumnail");
}
}
private string _DesScription;
[Column(DbType = "NTEXT")]
public string DesScription
{
get { return _DesScription; }
set
{
NotifyPropertyChanging("DesScription");
_DesScription = value;
NotifyPropertyChanged("DesScription");
}
}
private int _orderID;
[Column]
public int orderID
{
get { return _orderID; }
set
{
NotifyPropertyChanging("orderID");
_orderID = value;
NotifyPropertyChanged("orderID");
}
}
private string _pubDate;
[Column]
public string pubDate
{
get { return _pubDate; }
set
{
NotifyPropertyChanging("pubDate");
_pubDate = value;
NotifyPropertyChanged("pubDate");
}
}
private string _linkURL;
[Column]
public string linkURL
{
get { return _linkURL; }
set
{
NotifyPropertyChanging("linkURL");
_linkURL = value;
NotifyPropertyChanged("linkURL");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify that a property changed
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
#region INotifyPropertyChanging Members
public event PropertyChangingEventHandler PropertyChanging;
// Used to notify that a property is about to change
private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
{
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}
}
#endregion
}
when i Update Colum Thumnail , i have erros :
SQL Server does not handle comparison of NText, Text, Xml, or Image data types
because of special characters into database insert sequence trogn should I use BbType = "NTEXT"
Please Help me !
You could remove this column for concurrency checking by adding [Column(UpdateCheck = UpdateCheck.Never)] to this column.
See this blogpost about Linq to sql concurrency checking: http://blogs.msdn.com/b/matt/archive/2008/05/22/into-to-linq-to-sql-optimistic-concurrency.aspx

Raising a propertychanged event without adding a private variable

I have a property which looks like this.
public int NumberOfElephants { get; set; }
this property is in an observablecollection and it has to notify another property that it has changed.
how would i do the following
public int NumberOfElephants { get; set { OnPropertyChanged("totalAnimals"); }
without the code needing to be like this
private int _numberOfElephants;
public int NumberOfElephants {
get {
return _numberOfElephants;
}
set {
_numberOfElephants = value;
OnPropertyChanged("totalAnimals");
}
}
You don't. You can't.
Automatically implemented propertieS only work when the property is trivial - when no code is needed for the get/set beyond "return the variable's value" or "set the variable's value". You can make it shorter with reformatting, of course... I'd write that as:
private int numberOfElephants;
public int NumberOfElephants {
get { return numberOfElephants; }
set {
_numberOfElephants = value;
OnPropertyChanged("totalAnimals");
}
}
Actually, I'd use "opening brace on a line on its own" for the start of the set and the start of the property, but I've kept your favoured style for those. But having "single expression get/set implementations" on a single line can make classes with lots of properties much cleaner.
As an alternative to Jon's answer, you can get tools that will do this via IL weaving, such as NotifyPropertyWeaver, also available as a tool through the VS Gallery
For your sample, you should be able to have something like the following, according to their doco on Attributes:
[NotifyProperty(AlsoNotifyFor = new[] { "TotalAnimals" })]
public int NumberOfElephants { get; set; }
public int TotalAnimals { get; set; }
However, based on the example below from their site it might not be required depending on the implementation of TotalAnimals:
Your Code
public class Person : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
public string GivenNames { get; set; }
public string FamilyName { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
}
What gets compiled
public class Person : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string givenNames;
public string GivenNames
{
get { return givenNames; }
set
{
if (value != givenNames)
{
givenNames = value;
OnPropertyChanged("GivenNames");
OnPropertyChanged("FullName");
}
}
}
string familyName;
public string FamilyName
{
get { return familyName; }
set
{
if (value != familyName)
{
familyName = value;
OnPropertyChanged("FamilyName");
OnPropertyChanged("FullName");
}
}
}
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
public virtual void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Expanding on the answer by #jeffora
Using NotifyPropertyWeaver you could write this
public class Animals: INotifyPropertyChanged
{
public int NumberOfElephants { get; set; }
public int NumberOfMonkeys { get; set; }
public int TotalAnimals
{
get
{
return NumberOfElephants + NumberOfMonkeys;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
And this would be compiled
public class Animals : INotifyPropertyChanged
{
int numberOfElephants;
int numberOfMonkeys;
public int NumberOfElephants
{
get { return numberOfElephants; }
set
{
numberOfElephants = value;
OnPropertyChanged("TotalAnimals");
OnPropertyChanged("NumberOfElephants");
}
}
public int NumberOfMonkeys
{
get { return numberOfMonkeys; }
set
{
numberOfMonkeys = value;
OnPropertyChanged("TotalAnimals");
OnPropertyChanged("NumberOfMonkeys");
}
}
public int TotalAnimals
{
get { return NumberOfElephants + NumberOfMonkeys; }
}
public virtual void OnPropertyChanged(string propertyName)
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
{
propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
With tool like PostSharp you can weave the property to create the boiler plate code code. More, you don't have to implement the INotifyPropertyChanged, PostSharp can do it for you.
See this blog post.
I would use this in C#6
private int numberOfElephants;
public int NumberOfElephants {
get => numberOfElephants;
set {
_numberOfElephants = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
This needs
using System.Runtime.CompilerServices;

Categories

Resources