在ObservableCollection中更改模型属性时更新UI?

时间:2017-12-04 14:50:31

标签: c# xamarin mvvm xamarin.forms mvvm-light

我有一个视图,其中包含一组来自Web服务的图像 我在这个课程列表中收到它们:

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

在每张图片下我都会显示一个向上投票按钮,所以我在上面的模型中添加了另一个bool属性:

 public bool UpVoted { get; set; }

显示这些图片的ListView绑定到ObservableCollection<ImageModel >,我想通过将UpVoted的值转换为相应图标的转换器更改投票图标,用户单击投票图标:执行此方法的命令:

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

问题是UI没有更新,为了确保我理解了问题,我将模型转换为View模型,并对UpVoted属性进行了必要的更改(我使用的是MVVM灯库)

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

它现在有效, 所以我需要将UpVoted绑定到UI,因此无论何时更改

都会更新

3 个答案:

答案 0 :(得分:2)

第一 您的模型类必须继承自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 ); }
        }
    }

然后用MvxValueConverter准备好了

答案 1 :(得分:1)

穆斯塔法的回答提到了一个专门针对MvvmCross图书馆的课程 另一种选择是where

如果您希望编写自己的MVVM(或了解MVVM的工作原理), 一般模式是实现INotifyPropertyChanged:Implement Property Change NotificationI discuss here

实现INotifyPropertyChanged的一种简便方法是创建一个执行该实现的基类,然后从该基类继承。您可以使用该示例中的代码作为基类。或者使用稍微不同的实现,避免必须手动将属性名称作为字符串传递:

TinyMvvm

同样,上述代码的替代方法是使用现有的MVVM库。

对于另一种选择,不需要在所有属性设置器中编写“SetProperty(..)”或“OnPropertyChanged(..)”,谷歌有关使用{{3>的信息}}。那你就不需要上面的代码了;你的班级只会继承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)); } } 。 (在app启动时,你调用一个方法,将所需的逻辑“注入”所有INotifyPropertyChanged类的所有属性。)

确认:上面示例中的代码模式基于其中一个开源库。它可能来自TinyMvvm。

答案 2 :(得分:0)

您没有说明您正在使用哪种容器,但并非所有控件都设置为默认支持双向通知。所以你可能需要添加一个

Mode=TwoWay

从后端获取数据已更改的通知。或者,正如Mustafa先前的回答所示,您可能需要验证您的班级是否正在使用mvvm灯实施InotifyPropertyChanged事件。