How to observe multiple properties with Delegatecommand.ObservesProperty - c#

I would like to observe multiple properties in my viewmodel to check the CanExecute Method.
Question:
How to register more properties?
Example:
class MyViewModel
{
public int myproperty1 { get; set; }
public int myproperty2 { get; set; }
public DelegateCommand MyCommand { get; set; }
public MyViewModel()
{
MyCommand = new DelegateCommand(MyCommandMethod,CanExecuteMyCommandMethod);
MyCommand.ObservesProperty((() => myproperty1));
// line below doesnt work Exeception "Value is already observed". How to register more properties to observe?
MyCommand.ObservesProperty((() => myproperty2));
}
private bool CanExecuteMyCommandMethod()
{
throw new NotImplementedException();
}
private void MyCommandMethod()
{
throw new NotImplementedException();
}
}
Update:
PropertChanged event is done by Propertchanged.Fody INPC.
ObservesProperty is to RaiseCanExecuteChanged.
The second property observe registration raise a exception "Value is already observed).
Additional Question:
ObservesProperty((() => myproperty;
Allows multiple or single property?
If somebody else confirm multiple registration shall be possible?

Calling the ObservesProperty method for another property like you are doing should work. But you need to raise the PropertyChanged event in the setters of the source properties for the CanExecuteChanged event to be raised.
Please refer to the following sample code.
public class MyViewModel : BindableBase
{
private int _myproperty1;
public int myproperty1
{
get { return _myproperty1; }
set { _myproperty1 = value; RaisePropertyChanged(); }
}
private int _myproperty2;
public int myproperty2
{
get { return _myproperty2; }
set { _myproperty2 = value; RaisePropertyChanged(); }
}
public DelegateCommand MyCommand { get; set; }
public MyViewModel()
{
MyCommand = new DelegateCommand(MyCommandMethod, CanExecuteMyCommandMethod);
MyCommand.ObservesProperty((() => myproperty1));
MyCommand.ObservesProperty((() => myproperty2));
}
private bool CanExecuteMyCommandMethod()
{
return true;
}
private void MyCommandMethod()
{
}
}

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));
}
}

Update class property in xamarin Forms

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.

Raise event from Inner class to outer class in c#

I'm using MVVM pattern in my project.
My class design is like this:
Class Model : AbstractModel
{
InnerClass Iclass = new InnerClass();
Public String ModelProp1
{
get
{
return Iclass.prop1;
}
set
{
Iclass.prop1 = value;
}
}
public override void SetLabel(UInt16 value, int Index)
{
byte[] arr = BitConverter.GetBytes(value);
this.Iclass.IclassConfig[Index].Label = arr[0];
}
public override string DateFormat
{
get { return Iclass.intlDate.ToString(); }
set { Iclass.intlDate = Convert.ToByte(value); }
}
}
Class InnerClass
{
public byte intlDate
{
get { return this.intl_date; }
set { this.intl_date = value;
RaiseModelPropertiesChangedEvent(new ValueChangedEventArgs { Parameter_dateformat = this.intlDate });
}
private JClassa []channel_config = new JClass[2];
public JClass[] IclassConfig
{
get { return this.channel_config; }
set { this.channel_config = value; }
}
}
Public JClass
{
private byte channel_label;
public byte Label
{
get { return this.channel_label; }
set { this.channel_label = value;}
}
I'm getting data from other application. updated data is coming in InnerClass property from there I want to push this updated data to Model class.
Problem is coming for JClass property how can I fire event such that It will push updated data to model class.
For this I have created Event in InnerClass like this:
public event EventHandler<ValueChangedEventArgs> ModelPropertiesChanged;
public void RaiseModelPropertiesChangedEvent(ValueChangedEventArgs e)
{
if (ModelPropertiesChanged != null)
ModelPropertiesChanged(this, e);
}
public class ValueChangedEventArgs : EventArgs
{
public int Parameter_dateformat { get; set; }
public int Parameter_channelLabel { get; set; }
}
Tell me how Can I achieve this. Becuase I have 4 property in Jclass and 6 Property is InnerClass.
I would add event triggers in the setter of your inner class properties. Then in the Constructor of your parent class, move the IClass = new InnerClass() into your constructor and attach your event listeners.
Since you're MVVM you could leverage INotifyPropertyChanged, but heat will get messy in the long run.
Better to have a 'PropertyName'Changed event for each property you want to notify to the parent class.

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.

Categories

Resources