簡體   English   中英

在ObservableCollection中更改模型屬性時更新UI?

[英]Updating UI when a model property changes in an ObservableCollection?

我有一個視圖,我從一個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,因此只要它發生變化就會更新

首先,您的模型類必須從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准備好了

Mustafa的回答提到了一個特定於MvvmCross庫的類。
另一種選擇是TinyMvvm

如果您希望編寫自己的MVVM(或了解MVVM如何工作),一般模式是實現INotifyPropertyChanged: 實現屬性更改通知我在這里討論

實現INotifyPropertyChanged的一種便捷方法是創建一個執行該實現的基類,然后從該基類繼承。 您可以使用該示例中的代碼作為基類。 或者使用稍微不同的實現,避免必須手動將屬性名稱作為字符串傳遞:

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

同樣,上述代碼的替代方法是使用現有的MVVM庫。

對於另一種選擇, 這不需要在所有屬性設置器中寫入“SetProperty(..)”或“OnPropertyChanged(..)” ,谷歌有關使用Fody / PropertyChanged的信息 那你就不需要上面的代碼了; 你的類只會從INotifyPropertyChanged繼承。 (在app啟動時,你調用一個方法,將所需的邏輯“注入”所有INotifyPropertyChanged類的所有屬性。)

致謝:上面示例中的代碼模式基於其中一個開源庫。 它可能來自TinyMvvm。

您沒有說明您正在使用哪種容器,但並非所有控件都設置為默認支持雙向通知。 所以你可能需要添加一個

Mode=TwoWay

從后端獲取數據已更改的通知。 或者,正如Mustafa先前的回答所示,您可能需要驗證您的班級是否正在使用mvvm light實現InotifyPropertyChanged事件。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM