Relatively new to Xamarin Forms and trying to use Realm, as well, so forgive me if this is basic and easy to solve. My brain is currently fried trying to figure this out.
I have the following models:
public class State : RealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
public string StateShort { get; set; }
public string StateName { get; set; }
}
public class SalesOrder : RealmObject
{
[PrimaryKey]
[MapTo("_id")]
public ObjectId Id { get; set; } = ObjectId.GenerateNewId();
public string ContactName { get; set; }
public string ContactEmailAddress { get; set; }
public string CompanyName { get; set; }
public string Address { get; set; }
public string City { get; set; }
public State State { get; set; }
public string ZipCode { get; set; }
public string County { get; set; }
}
I have a Content Page for setting up a new Sales Order, as follows:
SalesOrderNewPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestRealm.Views.SalesOrderNewPage">
<ContentPage.Content>
<ScrollView>
<StackLayout Spacing="3" Padding="15">
<Label Text="Contact Name" FontSize="Medium" />
<Entry Text="{Binding ContactName, Mode=TwoWay}" FontSize="Medium" />
<Label Text="Contact Email" FontSize="Medium" />
<Editor Text="{Binding ContactEmailAddress, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
<Label Text="Company Name" FontSize="Medium" />
<Editor Text="{Binding CompanyName, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
<Label Text="Address" FontSize="Medium" />
<Editor Text="{Binding Address, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
<Label Text="City" FontSize="Medium" />
<Editor Text="{Binding City, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
<Label Text="State" FontSize="Medium" />
<Picker x:Name="StatePicker"
Title="--- select state ---"
ItemsSource="{Binding States}"
ItemDisplayBinding="{Binding StateShort}"
SelectedItem="{Binding SelectedState}" />
<Label Text="Zip Code" FontSize="Medium" />
<Editor Text="{Binding ZipCode, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
<Label Text="County" FontSize="Medium" />
<Editor Text="{Binding County, Mode=TwoWay}" AutoSize="TextChanges" FontSize="Medium" Margin="0" />
<Label Text="Application" FontSize="Medium" />
<Picker x:Name="ApplicationPicker"
Title="--- select application ---">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Application 1</x:String>
<x:String>Application 2</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
<StackLayout Orientation="Horizontal">
<Button Text="Cancel" Command="{Binding CancelCommand}" HorizontalOptions="FillAndExpand"></Button>
<Button Text="Save" Command="{Binding SaveCommand}" HorizontalOptions="FillAndExpand"></Button>
</StackLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
And the codebehind / .cs file for that xaml page
SalesOrderNewPage.xaml.cs
using MongoDB.Bson;
using System.Collections.Generic;
using TestRealm.Models;
using TestRealm.ViewModels;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TestRealm.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SalesOrderNewPage : ContentPage
{
public SalesOrder SalesOrder { get; set; }
public List<State> AllStates { get; set; }
public SalesOrderNewPage()
{
InitializeComponent();
var states = new List<State>()
{
new State { Id = ObjectId.GenerateNewId(), StateShort = "NY", StateName = "New York" },
new State { Id = ObjectId.GenerateNewId(), StateShort = "PA", StateName = "Pennsylvania" } ,
new State { Id = ObjectId.GenerateNewId(), StateShort = "VT", StateName = "Vermont" }
};
BindingContext = new SalesOrderNewViewModel();
}
protected override void OnAppearing()
{
base.OnAppearing();
}
}
}
And here is the View Model or the page
SalesOrderNewViewModel.cs
using MongoDB.Bson;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using TestRealm.Models;
using Xamarin.Forms;
namespace TestRealm.ViewModels
{
public class SalesOrderNewViewModel : BaseViewModel
{
private string contactname;
private string contactemailaddress;
private string companyname;
private string address;
private string city;
private string state;
private string zipcode;
private string county;
private List<State> states;
public ObservableCollection<State> States { get; set; }
public SalesOrderNewViewModel()
{
States = new ObservableCollection<State>();
SaveCommand = new Command(OnSave, ValidateSave);
CancelCommand = new Command(OnCancel);
this.PropertyChanged +=
(_, __) => SaveCommand.ChangeCanExecute();
}
private bool ValidateSave()
{
return !String.IsNullOrWhiteSpace(contactname)
&& !String.IsNullOrWhiteSpace(contactemailaddress)
&& !String.IsNullOrWhiteSpace(companyname);
}
public string ContactName
{
get => contactname;
set => SetProperty(ref contactname, value);
}
public string ContactEmailAddress
{
get => contactemailaddress;
set => SetProperty(ref contactemailaddress, value);
}
public string CompanyName
{
get => companyname;
set => SetProperty(ref companyname, value);
}
public string Address
{
get => address;
set => SetProperty(ref address, value);
}
public string City
{
get => city;
set => SetProperty(ref city, value);
}
### ERROR HERE ###
cannot implicity convert type 'string' to 'TestRealm.Models.State'
public State State
{
get => state;
set => SetProperty(ref state, value);
}
public string ZipCode
{
get => zipcode;
set => SetProperty(ref zipcode, value);
}
public string County
{
get => county;
set => SetProperty(ref county, value);
}
public Command SaveCommand { get; }
public Command CancelCommand { get; }
private async void OnCancel()
{
// This will pop the current page off the navigation stack
await Shell.Current.GoToAsync("..");
}
private async void OnSave()
{
SalesOrder salesOrder = new SalesOrder()
{
Id = ObjectId.GenerateNewId(),
ContactName = ContactName,
ContactEmailAddress = ContactEmailAddress,
CompanyName = CompanyName,
Address = Address,
City = City,
State = State,
ZipCode = ZipCode,
County = County
};
await DataStore.AddSalesOrderAsync(salesOrder);
// This will pop the current page off the navigation stack
await Shell.Current.GoToAsync("..");
}
}
}
And, of course, this is the BaseViewModel.cs file that I beleive most people are using with Xamarin Forms
BaseViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using TestRealm.Models;
using TestRealm.Services;
using Xamarin.Forms;
namespace TestRealm.ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
public IDataStore<SalesOrder> DataStore => DependencyService.Get<IDataStore<SalesOrder>>();
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
So, I am getting an error in the SalesOrderNewViewModel.cs file on the State, as it is not a string but is actually a property of State from the Model. I am not sure how to handle this at all and have found no guidance. I am trying to use a picker to pull the id property from the State Model, and display the StateName or StateShort in the Picker. However, it should set the property of id for the State in the SalesOrder model.
Sorry so clueless.
Any help is appreciated and thank you.