41639

Updating UI when a model property changes in an ObservableCollection?

I have a view that has a group of images I get from a web service I receive them in a list of this class:

public class ImageModel { public int Id { get; set; } public string Name { get; set; } public string imageUrl { get; set; } }

under each image I show an up-vote button, so I added another bool property to the model above:

public bool UpVoted { get; set; }

the ListView that shows these images is bound to an ObservableCollection<ImageModel > , I want to change the voting icon through a converter that convert the value of UpVoted to the corresponding icon, when the user click the voting icon: a command execute this method:

private void OnVoting(ImageModel image) { Images.Single(x => x.id == image.id).UpVoted = !image.UpVoted; }

the problem is that the UI is not updated, and to make sure that I understood the problem I turned the model to a View model and made the required changes to the UpVoted property (I'm using MVVM light library)

bool upVoted; public bool UpVoted { get { return upVoted; } set { Set(ref upVoted, value); } }

and it works now, so I need to bind the UpVoted to the UI, so it's updated whenever it changed

Answer1:

first your model class must inherit from MvxNotifyPropertyChanged

public class ImageModel : MvxNotifyPropertyChanged { public int Id { get; set; } public string Name { get; set; } private bool upVoted ; public bool UpVoted { get { return upVoted ; } set { upVoted = value; RaisePropertyChanged(() => UpVoted ); } } }

then with MvxValueConverter you ready to go

Answer2:

you do not say which sort of container that you are using but not all controls are set to support two way notification by default. so you may have to add a

Mode=TwoWay

to get notifications from the back end that data has changed. Or as the previous answer by Mustafa indicated you may need to verify that your class is implementing the InotifyPropertyChanged event with mvvm light.

Answer3:

Mustafa's answer mentions a class that is specific to MvvmCross library. Another alternative is TinyMvvm.

If you wish to write your own MVVM (or understand how MVVM works), the general pattern is to implement INotifyPropertyChanged: Implement Property Change Notification, which I discuss here.

A convenient way to implement INotifyPropertyChanged, is to make a base class that does that implementation, then inherit from that base class. You can use the code in that sample as your base class. Or use a slightly different implementation, that avoids having to manually pass the property name as a string:

using System.ComponentModel; using System.Runtime.CompilerServices; // Use this as base class for all your "view model" classes. // And possibly for your (domain) model classes. // E.g.: "public class MyLoginViewModel : HasNotifyPropertyChanged". // OR "public class MyLoginModel : HasNotifyPropertyChanged". // Give it whatever name you want, for ViewModels I suggest "ViewModelBase". public class HasNotifyPropertyChanged : INotifyPropertyChanged { // --- This is pattern to use to implement each property. --- // This works for any property type: int, Color, etc. // What's different from a standard c# property, is the "SetProperty" call. // You will often write an IValueConverter (elsewhere) to use in XAML to convert from string to your property type, // or from your property type to a type needed in your UI. // Comment out this example property if you don't need it. /// <summary> /// Set to "true" at end of your initialization. /// Then can use Property Trigger on Ready value=true in XAML to do something when your instance is ready for use. /// For example, load something from web, then trigger to update UI. /// </summary> private bool _ready; public bool Ready { get => _ready; set => SetProperty(ref _ready, value); } public event PropertyChangedEventHandler PropertyChanged; protected void SetProperty<T>(ref T property, T value, [CallerMemberName] string propertyName = null) { if (property == null || !property.Equals(value)) { property = value; RaisePropertyChanged(propertyName); } } protected void RaisePropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }

Again, an alternative to the above code is to use an existing MVVM library.

For another alternative, <strong>that doesn't require writing "SetProperty(..)" or "OnPropertyChanged(..)" in all of your property setters</strong>, google for info about using <strong>Fody/PropertyChanged</strong>. Then you wouldn't need any of the above code; your class would simply inherit from INotifyPropertyChanged. (And in app startup, you call a method that "injects" the needed logic into all properties of all INotifyPropertyChanged classes.)

Acknowledgement: The code pattern in example above is based on one of the open source libraries. It might be from TinyMvvm.

Recommend

  • css styling using custom attributes to make it more readable. good or bad?
  • Bind a DataGrid to the selectedrow object of a second datagrid, WPF Caliburn.Micro
  • Unable to override click events to anchor tag from a user created function
  • if statement in SQL to calculate age
  • AVAssetExportSession using AVAssetExportPresetPassthrough breaking output
  • How to synchronize two text box form values?
  • Combining Reports that use subreports already
  • Why the class instance value is corrupted in the multi-thread environment? [closed]
  • How do I apply one of two classes to an image depending on a certain condition in Rails 3?
  • Not able to read Object values in Freemarker Template
  • Setting inner div opacity to 1, but not effected
  • Dropdown menu with the dropdown-menu-right class does not align to the right
  • Looking for datastructure that maintains a size & purges older elements in the process
  • Ant: fileset “dir” attribute with a runtime expanded full path
  • Fixed Background Works in Chrome but Not Firefox?
  • Log4j cannot find properties file in a simple application
  • Monotouch crashes with NullReferenceException on non nullable object
  • Access object instance inside an event handler
  • Extract All Possible Paths from Expression-Tree and evaluate them to hold TRUE
  • How to get links to open in the native browser in iOS Meteor apps?
  • Hardware Accelerated Image Scaling in windows using C++
  • debug library loaded with ctypes using gdb
  • Combining SpatialPolygonsDataFrame of two neighbour countries
  • NHibernate Validation Localization with S#arp Architecture
  • Spring Data JPA custom method causing PropertyReferenceException
  • Why ng-show works with ng-repeat but ng-if doesn't? [duplicate]
  • Excel - Autoshape get it's name from cell (value)
  • Does CUDA 5 support STL or THRUST inside the device code?
  • How to apply VCL Styles to DLL-based forms in Inno Setup?
  • Adding custom controls to a full screen movie
  • Why winpcap requires both .lib and .dll to run?
  • How to set the response of a form post action to a iframe source?
  • Change div Background jquery
  • Qt: Run a script BEFORE make
  • Is there any way to bind data to data.frame by some index?
  • Django query for large number of relationships
  • reshape alternating columns in less time and using less memory
  • Why is Django giving me: 'first_name' is an invalid keyword argument for this function?
  • How can I use `wmic` in a Windows PE script?
  • How to push additional view controllers onto NavigationController but keep the TabBar?