Xamarin Shell : Pass multiple arguments to another page - c#

I have two pages in my Xamarin Forms Shell app.
One list page and another is the details page.
when I select the item in list page, the detail page will be shown. I was able to pass one parameter to the second page. I know how to pass the second value. But how should I receive the second value in the first property itself.
List Page:
async private void myLines_ItemTapped(object sender, ItemTappedEventArgs e)
{
var line = (Models.QLines)e.Item;
int pno = line.PageNo;
int lno = line.LineNo;
await Shell.Current.GoToAsync($"//mainTabs/pages?pageno={pno}&lineno={lno}");
}
Detail Page:
public int CurrentPage { get; set; }
public int CurrentLine { get; set; }
public bool IsFromSearchPage { get; set; }
public string PageNo
{
set
{
CurrentPage = Convert.ToInt32(Uri.UnescapeDataString(value));
IsFromSearchPage = true;
LoadPagesAsSingle();
}
}
public string LineNo
{
set
{
CurrentLine = Convert.ToInt32(Uri.UnescapeDataString(value));
}
}
public MyPages()
{
InitializeComponent();
conn = DependencyService.Get<ISQLiteMyConnection>().GetConnection();
IsFromSearchPage = false;
LoadPagesAsSingle();
}

As explained in https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/shell/navigation#pass-data you can use QueryProperty attribute to map between queryID and the target property:
[QueryProperty("Pageno", "pageno")]
[QueryProperty("Lineno", "lineno")]
public partial class DetailPage: ContentPage
{
private int _Pageno;
public int Pageno
{
get { return _Pageno; }
set { _Pageno = value; }
}
private int _Lineno;
public int Lineno
{
get { return _Lineno; }
set { _Lineno = value; }
}

As another solution you can pass parameters through static members of page. For example page may contain static ViewModel object, which will be initialized before page appears.
public class ViewModel : ViewModelBase
{
public string Text { get; set; }
public int Number { get; set; }
}
public class MyPage : Page
{
static ViewModel _viewModel = new ViewModel();
public MyPage()
{
BindingContext = _viewModel;
}
public static void InitPage(string text, int number)
{
_viewModel.Text = text;
_viewModel.Number = number;
}
}
}
Code inside caller
static async Task GotoPage()
{
MyPage.InitPage("Text", 123);
await Shell.Current.GoToAsync($"//mainTabs/pages");
}

you can use parameters in the detailPage
public DetailPage(string val1,string val2)
{
}
then call it in MyPage
Navigation.PushAsync(new DetailPage("parameter1","parameter2"));

Related

Sharing Object between Views & ViewModels in MVVM

I'm new to WPF + MVVM and have been having trouble getting around viewmodels.
I have a object called FSystem which contains a alot of lists which are populated from a XML.
public class FSystem : ObservableObject
{
public List<FUser> _userList;
public List<FZone> _zoneList;
public List<FSource> _sourceList;
public string _projectName { get; set; }
private string _projectVersion { get; set; }
private string _processorIp { get; set; }
private bool _isMultiLingualModeOn { get; set; }
private int _systemIncludeLighting { get; set; }
private int _systemIncludeWindowsTreatments { get; set; }
private int _systemIncludeSip { get; set; }
private int _systemIncludeCamaras { get; set; }
public FSystem()
{
UserList = new List<FUser>();
}
}
This is the XMLParser which is called when the user loads the XML to the application.
public static class XMLParsers
{
public static FSystem ParseByXDocument(string xmlPath)
{
var fSystem = new FSystem();
XDocument doc = XDocument.Load(xmlPath);
XElement fSystemElement = doc.Element("FSystem");
if (fSystemElement != null)
{
fSystem.ProjectName = fSystemElement.Element("ProjectName").Value;
fSystem.ProjectVersion = fSystemElement.Element("ProjectVersion").Value;
fSystem.ProcessorIp = fSystemElement.Element("ProcessorIP").Value;
fSystem.ProcessorFilePath = fSystemElement.Element("ProcessorFilePath").Value;
fSystem.SystemIncludeLighting = Convert.ToInt16(fSystemElement.Element("SystemIncludeLighting").Value);
fSystem.SystemIncludeSip = Convert.ToInt16(fSystemElement.Element("SystemIncludeLighting").Value);
fSystem.SystemIncludeCamaras = Convert.ToInt16(fSystemElement.Element("SystemIncludeCameras").Value);
}
fSystem.UserList = (from user in doc.Descendants("FUser")
select new FUser()
{
Id = user.Element("Id").Value,
Name = user.Element("Name").Value,
Icon = user.Element("IconColour").Value,
Pin = user.Element("UserPin").Value,
IsPinEnabled = Convert.ToBoolean(Convert.ToInt16(user.Element("UserPinEnabled").Value)),
ListIndex = user.Element("ListIndex").Value
}).ToList();
return fSystem;
}
}
And this is the MainViewModel below is what contains the Commands which Load the XML and the property FSystem I wish to use in other view models.
public class MainViewModel : ViewModel
{
private Fystem fSystem;
public FSystem FSystem
{
get { return fSystem; }
private set
{
fSystem = value;
NotifyPropertyChanged("FSystem");
}
}
public MainViewModel()
{
InitiateState();
WireCommands();
}
private void InitiateState()
{
FSystem = new FSystem();
}
private void WireCommands()
{
XDocumentLoadCommand = new RelayCommand(XDocumentLoad) {IsEnabled = true};
ClearDataCommand = new RelayCommand(ClearData) {IsEnabled = true};
}
public RelayCommand XDocumentLoadCommand { get; private set; }
private void XDocumentLoad()
{
var openDlg = new OpenFileDialog
{
Title = "Open .FAS",
DefaultExt = ".fas",
Filter = "F System Files (*.fas)|*.fas",
Multiselect = false
};
bool? result = openDlg.ShowDialog() == DialogResult.OK;
if (result != true) return;
FSystem = XMLParsers.ParseByXDocument(openDlg.FileName);
}
The application basically lets the user change the different objects (FUser,FZone,FSource, ect). The idea I had was the user would load the XML then be able to edit the different list objects on different views.
What would the correct way be to go about this in MVVM?
I plan to (hopefully) get the User, Zone and Source views to display Datagrids which are populated with their respective data from the Model.
Create you specific view models, and use dependency injection to pass the relevant data into them (this list or that list).
This way, the view models don't need to know about other stuff, and you can easily mock it for testing and for dummy data to see on the designer.
Copy paste into Linqpad for the simplest example. Both mock viewmodels take a dependency (i in our case). You can just pass your lists:
void Main()
{
int someInt = 5;
int anotherInt = 7;
VM vm1 = new VM(someInt);
VM vm2 = new VM(anotherInt);
vm1.RevealI();
vm2.RevealI();
}
public class VM{
private int _i;
public VM(int i)
{
_i = i;
}
public void RevealI() { Console.WriteLine("value of i is: " + _i); }
}
Othen than that, here's more items:
MSDN
Code Project
stack overflow

My ViewModel changes are not reflected in my UI

I have two bound textboxes in my View.
<TextBox Text="{Binding BookingWizard.CustomerView.Email,Mode=TwoWay}" />
<TextBox Text="{Binding BookingWizard.CustomerView.ContactNo,Mode=TwoWay}" />
I can populate these fields when another textbox has lost its focus. the code behind for that bit is:
private void txtFirstName_LostFocus(object sender, RoutedEventArgs e)
{
LookUpEmailAndContactNo();
}
private void LookUpEmailAndContactNo()
{
var vm = this.DataContext as ApplicationViewModel;
var customer = vm.BookingWizard.LookUpEmailAndContactNo();
//etc
vm.BookingWizard.CustomerView.Email = customer.Email;
}
public Customer LookUpEmailAndContactNo()
{
var res= InformedWorkerBusinessService.Customer.GetEmailAndContactNo(CustomerView.FName, CustomerView.SName);
if (res!=null)
{
CustomerView.Email = res.Email;
CustomerView.ContactNo = res.ContactNo;
}
return CustomerView;
}
This is the screenshot of my data context when i set a break-point in the LookUpEmailAndContactNo event:
As you can see the data context does have these values but I cannot see what is wrong with my UI binding?
ADDITIONAL:
I set my view model at the App entry point:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
ApplicationView app = new ApplicationView();
ApplicationViewModel context = new ApplicationViewModel();
context.ActiveRecord = new ActiveRecord();
context.CustomerSearch = new CustomerSearch();
context.BookingWizard = new BookingWizard();
context.BookingWizard.CustomerView = new InformedWorkerModel.Customer();
context.BookingWizard.JobView = new InformedWorkerModel.Job();
app.DataContext = context;
app.Show();
}
}
This is inside my BookingWizard class:
public class BookingWizard : ViewModelBase, IDataErrorInfo
{
Customer _Customer;
public bool IsExistingCustomer { get; set; }
public IEnumerable<string> FNames
{
get
{
if (CustomerView.SName == null)
{
CustomerView.SName = string.Empty;
}
return InformedWorkerBusinessService.Customer.GetFirstNames(CustomerView.SName);
}
}
public Customer LookUpEmailAndContactNo()
{
var res= InformedWorkerBusinessService.Customer.GetEmailAndContactNo(CustomerView.FName, CustomerView.SName);
if (res!=null)
{
CustomerView.Email = res.Email;
CustomerView.ContactNo = res.ContactNo;
}
return CustomerView;
}
public Customer CustomerView
{
get { return _Customer; }
set
{
_Customer = value; RaisePropertyChanged("CustomerView");
}
}
}
and in my Customer Class:
[Table("Customer")]
public class Customer
{
[AutoIncrement]
[PrimaryKey]
public int CustomerId { get; set; }
public string SName { get; set; }
public string FName { get; set; }
public string ContactNo { get; set; }
public string Email { get ; set; }
}

Change data with buttonclick - MVVM

I have a ListView with an List<List<enum>> property and i have a View that shows each bool as button.
I want to cycle through the bound enum when someone clicks on the button. The problem is I cant use a normal click because it would be outside of my ViewModel.
Edit:
I have the class TruthTable that has 2 DynTable:
public sealed class Column<T>
{
public Column()
{
ColumnData = new List<T>();
ColumnHeader = "";
}
...
public List<T> ColumnData { get; set; }
public string ColumnHeader { get; set; }
}
public sealed class DynTable<T>
{
public DynTable()
{
Columns = new List<Column<T>>();
}
...
public List<Column<T>> Columns { get; set; }
}
public sealed class TruthTable
{
public TruthTable()
{
input = new DynTable<bool>();
results = new DynTable<BoolState>();
}
...
private DynTable<bool> input;
private DynTable<BoolState> results;
public DynTable<bool> Input { get { return input; } set { input = value; } }
public DynTable<BoolState> Results { get { return results; }}
}
public enum BoolState
{
False = 0,
True = 1,
DontCare = 2
}
And i have a ViewModel for the TruthTable. I dont think that the I have to show the code for the ViewModel because its just a TruthTable property. I hope thats enough code to understand my problem ._.

How to set values of user control from class

I have a user control and their are many textbox on it. I add this user control to a different project and I can use it, when I write every property on UserControl. I want to set textbox fields of this user control with using a class. These are my codes:
Class:
namespace IEUserControl
{
public class IEValue
{
public string IsEmriNo { get; set; }
public string Nevi { get; set; }
public string BrutKg { get; set; }
public string NetKg { get; set; }
}
}
User Control:
namespace IsEmriUserControl
{
public partial class UC_IsEmri : UserControl
{
public UC_IsEmri()
{
InitializeComponent();
}
//private IsEmriValue _isEmri;
//public IsEmriValue isEmri
//{
// get
// {
// return _isEmri;
// }
// set
// {
// _isEmri = value;
// }
//}
public string IsEmriNo
{
get { return txtIsEmriNo.Text; }
set { txtIsEmriNo.Text = value; }
}
public string Nevi
{
get { return txtNevi.Text; }
set { txtNevi.Text = value; }
}
public string BrutKg
{
get { return txtBrutKg.Text; }
set { txtBrutKg.Text = value; }
}
public string NetKg
{
get { return txtNetKg.Text; }
set { txtNetKg.Text = value; }
}
}
}
When I use properties, I can set textbox values. However I want to set my textbox values with my Class. Can anyone give me an example setting textbox values with using class? Thank you.
Make a method/property like this
public IEValue IE_Value
{
get
{
return new IEValue() {
IsEmrino = txtIsEmriNo.Text,
Nevi = txtNevi.Text,
BrutKg = txtBrutKg.Text,
NetKg = txtNetKg.Text
};
}
set
{
txtIsEmriNo.Text = value.IsEmrino;
txtNevi.Text = value.Nevi;
txtBrutKg.Text = value.BrutKg;
txtNetKg.Text = value.NetKg;
}
}

Constructors GetInfo

I am new to C# and am working on classes and understanding them. My problem is I am not understanding how to create a Get to retrieve the private variable _yourname and Set to set the private variable _yourname.
namespace WindowsFormsApplication1
{
class InputClass
{
private string _yourName;
public string _banner;
public virtual void GetInfo();
public InputClass(String _banner)
{
_banner = "Enter your name";
}
}
}
Maybe I am using the wrong function to GetInfo. But I am also wondering when I have the GetInfo if in the () I should write _yourname in it.
In C# there are properties, which have the function of public getter and setter methods in other languages:
class InputClass
{
private string _yourName;
public string _banner;
public InputClass(String _banner)
{
this._banner = _banner;
}
public string YourName
{
get { return _yourName; }
set { _yourName = value; }
}
}
But you can use auto properties, if you want:
class InputClass
{
public InputClass(String _banner)
{
Banner = _banner;
}
public string YourName
{
get; set;
}
public string Banner
{
get; set;
}
}
It sounds like you are trying to provide access to the _yourName field. If so then just use a property
class InputClass {
public string YourName {
get { return _yourName; }
set { _yourName = value; }
}
...
}
Now consumers of InputClass can access it as if it were a read only field.
InputClass ic = ...;
string yourName = ic.YourName;
ic.YourName = "hello";
Note: C# provides a special syntax for simple properties like this which are just meant to be wrappers over private fields. It's named auto-implemented properties
class InputClass {
public string YourName { get; set; }
}
You can override getters and settings using the get and set keywords. For example:
class InputClass
{
private string _yourName;
private string _banner;
public YourName
{
get { return _yourName; }
set { _yourName = value; }
}
public Banner
{
get { return _banner; }
set { _banner = value; }
}
public InputClass(String banner)
{
_banner = banner;
}
}
1.) Use properties instead of members, you get a free accessor (get) and mutator (set).
public string YourName { get; set; }
public string Banner { get; set; }
2.) You can take advantage of the default constructor, and declare it on the fly.
//the old way:
InputClass myClass = new InputClass();
myClass.YourName = "Bob";
myClass.Banner = "Test Banner";
//on the fly:
InputClass myClass = new InputClass()
{
YourName = "Bob",
Banner = "Test Banner"
}

Categories