在Realm中使用特定于项目的ViewModel的最佳方法是什么?

时间:2017-09-17 18:49:28

标签: c# mvvm uwp realm

我移植了我的应用程序以使用Realm数据库而不是SQLite。但是我遇到了IRealmCollection与MVVM结合的问题。

让我们假设以下模型:

public class Item : RealmObject
{
    public string Id { get; }
}

MainViewModel的当前方法就是这样:

public class MainViewModel
{
    public IRealmCollection<Item> { get; private set; }
}

我现在面临的问题是Item具有位于ItemViewModel的特定命令。我希望在保留IRealmCollection

的功能的同时使用这些功能

ItemViewModel

public class ItemViewModel
{
    public Item Model { get; private set; }
    public ICommand MyCommand { get; private set; }
}

我一直在考虑几种方法,但我想知道是否有更简单的解决方案:

  • 创建订阅Realm的自定义ObservableCollection
  • 使用LINQ .Select()扩展名从列表中创建ViewModel
  • ItemViewModel保存在Realm中,并将[Ignored]属性添加到每个其他属性或命令
  • 将逻辑从ItemViewModel移出到单独的类(如ItemHelper)并从MainViewModel
  • 调用该逻辑

解决此问题的最佳方式和最可能是MVVM方式是什么?

1 个答案:

答案 0 :(得分:1)

如果您的命令和其他属性很简单,并且可以嵌入到持久性Item中,我会使用该解决方案。例如,这可能并不总是有效,因为RealmObjects是在访问集合中的索引时动态创建的。 E.g:

var collection = realm.All<Item>();
var a = collection.ElementAt(0);
var b = collection.ElementAt(0);

会为ab提供不同的实例。这意味着您不能依赖RealmObject继承者中的非持久状态。如果这是一个交易破坏者,那么我会建议一个自定义的ObservableCollection包装IRealmCollection并处理您的ViewModel的投影,然后可以使用合成来公开RealmObject:

public interface IViewModel<T> where T : RealmObject
{
    T Item { get; set; }
}

public class MyObservableCollection<TViewModel, TRealmObject> : IReadOnlyList<TViewModel>, INotifyCollectionChanged
    where TRealmObject : RealmObject
    where TViewModel : IViewModel<TRealmObject>, new()
{
    private readonly IRealmCollection<TRealmObject> _collection;

    public TViewModel this[int index] => Project(_collection[index]);

    private event PropertyChangedEventHandler _propertyChanged;
    public event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add
        {
            UpdateCollectionChangedSubscriptionIfNecessary(isSubscribed: true);
            _collectionChanged += value;
        }
        remove
        {
            _collectionChanged -= value;

            UpdateCollectionChangedSubscriptionIfNecessary(isSubscribed: false);
        }
    }

    public MyObservableCollection(IRealmCollection<TRealmObject> collection)
    {
        _collection = collection;
    }

    private TViewModel Project(TRealmObject obj)
    {
        return new TViewModel
        {
            Item = obj
        };
    }

    private void UpdateCollectionChangedSubscriptionIfNecessary(bool isSubscribed)
    {
        if (_collectionChanged == null)
        {
            if (isSubscribed)
            {
                // Subscribe via _collection
            }
            else
            {
                // Unsubscribe via _collection
            }
        }
    }
}