Update class property in xamarin Forms - c#

I am working on mobile app using xamarin forms, I have a list of object. I have added the rows in list and raise property using this OnPropertyChanged and after save the items i want to update the status of list of object property. How we can update Status Property, Here is my code example , please check the code and update me, Thanks:-
class Test
{
public int ID{ get; set; }
public string Name { get; set; }
public bool Status { get; set; }
}
class Consume : BaseViewModel
{
void main()
{
ObservableCollection<Test> coll = new ObservableCollection<Test>();
coll = await db.GetData();
foreach (var item in coll)
{
item.Status = true;
//How we can update Status property of class
OnPropertyChanged("Status");
}
}
}

Implement INotifyPropertyChanged in your Test class:
class Test : INotifyPropertyChanged
{
public int ID { get; set; }
public string Name { get; set; }
private bool _status;
public bool Status
{
get { return _status; }
set
{
_status = value;
RaisePropertyChanged();
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName]string propertyName = "")
{
Volatile.Read(ref PropertyChanged)?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
And if you have correct binding, after item.Status = true; UI will get change of this property.

Related

How to work with a model in viewModel

I'm having a problem with using MVVM for a Xamarin project.
I can not refresh the user interface if one of my objects in my viewModel is updated (after a PUT request, for example).
Let me explain :
My model :
public class MyObject
{
public string Id { get; private set; }
public string Name { get; private set; }
}
My viewmodel :
public class MyViewModel : BaseViewModel
{
public MyObject MyObject { get; private set; }
public string IdMvvm
{
set
{
if (this.MyObject.Id != value)
{
MyObject.Id = value;
OnPropertyChanged(nameof(IdMvvm));
}
}
get { return MyObject.Id; }
}
public string NameMvvm
{
set
{
if (this.MyObject.Name != value)
{
MyObject.Name = value;
OnPropertyChanged(nameof(NameMvvm));
}
}
get { return MyObject.Name; }
}
}
BaseViewModel implements INotifyPropertyChanged
public class BaseViewModel : INotifyPropertyChanged
{
public string PageTitle { get; protected set; }
LayoutViewModel() {}
// MVVM ----------------------------------------------------------------------------------------
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected void SetValue<T>(ref T backingField, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(backingField, value))
return;
backingField = value;
OnPropertyChanged(propertyName);
}
MyViewModel is defined as BindingContext for my page
My properties IdMvvm and NameMvvm are bind in Entry in my page in xaml
When I modify an Entry then the value is raised but if my MyModel object changes value, for example update (click on a button) then the value of the different Entry is not updated
Can you help me please? Because it seems that I missed something ...
If you need more explanation, tell me to know
Sorry if my english is not good
It is because when you change the model, your view is not aware about the change. Update your code so that you explicitly notify property changes when your model changes.
public class MyViewModel : BaseViewModel
{
private MyObject _myObject;
public MyObject MyObject
{
get { return _myObject; }
private set { _myObject = value; NotifyModelChange(); }
}
public string IdMvvm
{
set
{
if (this.MyObject.Id != value)
{
MyObject.Id = value;
OnPropertyChanged(nameof(IdMvvm));
}
}
get { return MyObject.Id; }
}
public string NameMvvm
{
set
{
if (this.MyObject.Name != value)
{
MyObject.Name = value;
OnPropertyChanged(nameof(NameMvvm));
}
}
get { return MyObject.Name; }
}
private void NotifyModelChange()
{
OnPropertyChanged(nameof(IdMvvm));
OnPropertyChanged(nameof(NameMvvm));
}
}

Passing parameters from Detail to MainViewModel in MVVMCross

I have two views : MainView and DetailView. I have a list of items to display and when user select an item and I am passing item properties to DetailViewModel and user could able to update these values.
Everything works so far, but I wonder how am I passing back to updated values to the MainViewModel ?
MainViewModel.cs
public MainViewModel SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
ShowViewModel<DetailViewModel>(
new DetailViewModel.Parameter
{
Date = Date,
Age = _selectedItem.Age,
Category = _selectedItem.Category,
Discount = _selectedItem.Discount,
}
);
RaisePropertyChanged(() => SelectedItem);
}
}
DetailViewModel.cs
public class DetailViewModel: MvxViewModel
{
public double Age { get; set; }
public double Category { get; set; }
public double Discount { get; set; }
public class Parameter
{
public DateTime Date { get; set; }
public double Age { get; set; }
public int Category{ get; set; }
public double Discount { get; set; }
}
public void Init(Parameter param)
{
Age = param.Age;
Category = param.Category;
Discount = param.Discount ;
}
}
One way to pass variables between ViewModels is a Messenger based solution.
MvvmCross Messenger can be found in NuGet.
MainViewModel
private readonly IMvxMessenger _messenger;
private readonly MvxSubscriptionToken _token;
public MainViewModel(IMvxMessenger messenger) {
_messenger = messenger;
_token = messenger.Subscribe<SelectedItemMessage>(OnMessageReceived);;
}
private void OnMessageReceived(SelectedItemMessage obj)
{
SelectedItem = obj.SelectedItem;
}
DetailViewModel
private readonly IMvxMessenger _messenger;
public DetailViewModel(IMvxMessenger messenger) {
_messenger = messenger;
}
public void YourUpdateMethod() {
var message = new SelectedItemMessage(this, SelectedItem); //SelectedItem assumed it is a ViewModel property.
_messenger.Publish(message, typeof(SelectedItemMessage));
}
SelectedItemMessage
public class SelectedItemMessage : MvxMessage
{
public SelectedItemMessage(object sender, SelectedItem selectedItem) : base(sender)
{
SelectedItem = selectedItem;
}
public SelectedItem SelectedItem { get; set; }
}
Take a look at http://slodge.blogspot.nl/2013/05/n9-getting-message-n1-days-of-mvvmcross.html for a full guide to MvvmCross Messenges.
Edit using age and category in Message
public SelectedItemMessage(object sender, double age, int category) : base(sender)
{
Age = age;
Category = category;
}
public double Age { get; set; }
public int Category{ get; set; }
}
Changing the MainViewModel OnMessageReceived method
private void OnMessageReceived(SelectedItemMessage obj)
{
Age = obj.Age;
Category= obj.Category;
}
Why not just keep a reference to DetailViewModel when you create it in MainViewModel? Then any values changed in the DetailViewModel instance will be available via that reference in MainViewModel.
private DetailViewModel _detailVM;
public MainViewModel SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
_detailVM = new DetailViewModel.Parameter {
Date = Date,
Age = _selectedItem.Age,
Category = _selectedItem.Category,
Discount = _selectedItem.Discount
};
ShowViewModel<DetailViewModel>(_detailVM);
RaisePropertyChanged(() => SelectedItem);
}
}

Implement many INotifyPropertyChanged

please tell me best way to implement many duplicate INotifyPropertyChanged.
I have a MainClass that has 10 children, every child has six field and every field must fired property change when own value changed.
this my code but not work:
public class BaseModel
{
public string S1 { get; set; }
public string S2 { get; set; }
public string S3 { get; set; }
public string S4 { get; set; }
public string S5 { get; set; }
public string S6 { get; set; }
}
and I use a class named ViewModelBase to implement INotifyPropertyChanged.
in second step use a class to implement duplicate INotifyPropertyChanged:
public class ImplementBaseModel : ViewModelBase
{
private readonly BaseModel _baseModel;
public ImplementBaseModel()
{
_baseModel = new BaseModel();
}
public string S1
{
get { return _baseModel.S1; }
set
{
if (_baseModel.S1 == value)
return;
_baseModel.S1 = value;
base.OnPropertyChanged("S1");
}
}
public string S2
{
get { return _baseModel.S2; }
set
{
if (_baseModel.S2 == value)
return;
_baseModel.S1 = value;
base.OnPropertyChanged("S2");
}
}
// other code...
}
then a model has 10 of this class:
public class MidClass
{
public ImplementBaseModel ImplementBaseModel1 { get; set; }
public ImplementBaseModel ImplementBaseModel2 { get; set; }
// other field
public ImplementBaseModel ImplementBaseModel10 { get; set; }
public MidClass()
{
ImplementBaseModel1 = new ImplementBaseModel();
ImplementBaseModel2 = new ImplementBaseModel();
// ....
ImplementBaseModel10 = new ImplementBaseModel();
}
}
OK finish code! now please tell me why some property not fired when value change? is a best way to implement this code?
In your setters, you never actually set the value. Use:
public string S1
{
get { return _baseModel.S1; }
set
{
if (_baseModel.S1 == value)
return;
baseModel.S1 = value;
OnPropertyChanged("S1");
}
}
Note that I removed the base from OnPropertyChanged. It isn't normal to invoke the PropertyChanged event in this way.
All NotifyPropertyChanged does is cause every binding to perform a "get" on their bound property. If the backing field is never updated, they will just get the same data.
as a shortcut, you could also create a local method like
bool UpdateAndRaiseIfNecessary( ref string baseValue, string newValue, [CallerMemberName] string propertyName = null)
{
if (baseValue != newValue)
{
baseValue = newValue;
OnPropertyChanged( propertyName );
return true;
}
return false;
}
and then all of the setters would be like this:
set
{
this.UpdateAndRaiseIfNecessary( ref _baseModel.S1, value );
}

Caliburn Micro : passing Object between ViewModel

I'm developing a simple Crud Application (a windows 8.1 store application) using Caliburn Micro 2.0.0-alpha2
I'm in trouble with navigation between viewmodels, passing object.
I read many times the solution proposed by
Anders Gustafsson (How to pass parameter to navigated view model with WinRT Caliburn.Micro?)
and i tried to adapt it to my scope.
But the object is alwais null.
I need to pass a single object selected from a listView to my crudPage.
The crudPage is composed by an userControl that shown the FormView.
So i want to initialize this Form, with the values of the passed object.
I think that the problem is that the "Parameter" is initialized only after the ViewModel is created, but i don't know how to fix that problem.
There is my code, according with the idea of Anders Gustafsson
TransporterListViewModel (a list of Transporters from Database)
public class TransporterListViewModel : ViewModelBase
{
public string Title { get; set; }
public TransporterListViewModel(INavigationService navigationService)
: base(navigationService)
{
LoadData();
}
public async void LoadData() {
_transporters = await TransporterService.GetAll();
}
private BindableCollection<Transporter> _transporters;
public BindableCollection<Transporter> Transporters
{
get
{
return this._transporters;
}
set
{
this._transporters = value;
NotifyOfPropertyChange(() => this.Transporters);
}
}
private Transporter _selectedItem;
public Transporter SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
NotifyOfPropertyChange(() => this.SelectedItem);
navigationService.Navigated += NavigationServiceOnNavigated;
navigationService.NavigateToViewModel<TransporterCrudPageViewModel>(_selectedItem;);
navigationService.Navigated -= NavigationServiceOnNavigated;
}
}
private static void NavigationServiceOnNavigated(object sender, NavigationEventArgs args)
{
FrameworkElement view;
TransporterCrudPageViewModel transporterCrudPageViewModel;
if ((view = args.Content as FrameworkElement) == null ||
(transporterCrudPageViewModel = view.DataContext as TransporterCrudPageViewModel) == null) return;
transporterCrudPageViewModel.InitializeTransporterForm(args.Parameter as Transporter);
}
TransporterCrudViewModel (the page that cointains the UserControl to initialize)
public class TransporterCrudPageViewModel : ViewModelBase
{
public string Title { get; set; }
public Transporter Parameter { get; set; }
public TransporterFormViewModel TransporterFormVM { get; set; }
public async void InitializeTransporterForm(Transporter enumerable)
{
TransporterFormVM = new TransporterFormViewModel(navigationService, enumerable);
await SetUpForm(enumerable);
}
public async Task SetUpForm(Transporter t){
TransporterFormVM.trName = t.trName;
TransporterFormVM.trUrl = t.trUrl;
}
public TransporterCrudPageViewModel(INavigationService navigationService)
: base(navigationService)
{
Title = "TransporterCrud Page";
//this.navigationService = navigationService;
this.InitializeTransporterForm(Parameter);
}
TransporterFormViewModel (the userContol to initialize)
public class TransporterFormViewModel :ViewModelBase
{
public string Title { get; set; }
public Transporter Transporter { get; set; }
public TransporterFormViewModel(INavigationService navigationService,Transporter trans)
: base(navigationService)
{
Transporter = trans;
}
private string _trName;
public string trName
{
get
{
return _trName;
}
set
{
_trName = value;
NotifyOfPropertyChange(() => trName);
}
}
public string trCode { get; set; }
public string trUrl { get; set; }
public int trId { get; set; }
In the constructor TransporterCrudViewModel class you have:
this.InitializeTransporterForm(Parameter);
where Parameter is a property of type Transporter not initialized and you will call the method InitializeTransporterForm with a null parameter. Then you'll call SetUpForm method with a null value of the parameter Transporter t. I think you should initialize in some way this property.
Then, supposing you're continuing in your TransporterListViewModel class with this:
transporterCrudPageViewModel.InitializeTransporterForm(args.Parameter as Transporter);
in the method InitializeTransporterForm, you don't set the passed parameter as value of the property Parameter with something like this:
public async void InitializeTransporterForm(Transporter enumerable)
{
TransporterFormVM = new TransporterFormViewModel(navigationService, enumerable);
this.Parameter = enumerable; //setting the Parameter property..
await SetUpForm(enumerable);
}
Beside these notes, you should put a breakpoint with your IDE in the line
transporterCrudPageViewModel.InitializeTransporterForm(args.Parameter as Transporter);
Make sure that the property Parameter of the NavigationEventArgs object is not null.

C# Datagridview Binding to a Class not updating

I have a datagridview that I am binding to a class. I add to the class but the datagridview is not updating.
My bind:
ScannedChecks = new ScannedChecks();
ScannedChecks.AddCheck(DateTime.Now, "22222", "checknumdd", "routingdd", _checkData, 4);
dataGridView1.DataSource = ScannedChecks;
I went ahead and did the AddCheck to see if it was reaching the datagridview and it isn't... The class is being updated though.
My class:
namespace SSS.Ckentry
{
public class ScannedChecks : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ScannedChecks()
{
ScannedChecksCollection = new ObservableCollection<ScannedCheck>();
}
public void AddCheck(DateTime checkDate, string accountNumber, string checkNumber, string bankRoutingNumber, string bankAccountNumber, decimal checkAmount)
{
var scc = new ScannedCheck
{
CheckDate = checkDate,
AccountNumber = accountNumber,
CheckNumber = checkNumber,
BankRoutingNumber = bankRoutingNumber,
BankAccountNumber = bankAccountNumber,
CheckAmount = checkAmount,
};
ScannedChecksCollection.Add(scc);
}
public ObservableCollection<ScannedCheck> ScannedChecksCollection { get; set; }
public class ScannedCheck
{
public DateTime CheckDate { get; set; }
public string AccountNumber { get; set; }
public string CheckNumber { get; set; }
public string BankRoutingNumber { get; set; }
public string BankAccountNumber { get; set; }
public decimal CheckAmount { get; set; }
}
}
}
Can anyone tell me what I am doing wrong?
Thanks much!
If you ever replace the ScannedChecksCollection with a new ScannedChecksCollection, the property setter should fire the PropertyChanged exent.
private ObservableCollection<ScannedCheck> scannedChecksCollection;
public ObservableCollection<ScannedCheck> ScannedChecksCollection {
get
{
return scannedChecksCollection;
}
set
{
if (value != scannedChecksCollection)
{
value = scannedChecksCollection;
NotifyPropertyChanged("ScannedChecksCollection");
}
}
}
private void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
If checks are modifiable, ScannedCheck should implement INotifyPropertyChanged
Shouldn't you be doing
dataGridView1.DataSource = ScannedChecks.ScannedChecksCollection;

Categories

Resources