0

この答えは私の問題の解決策だと思いますが、それを私の問題に適用する方法を理解するのに苦労しています。他の投稿と同様に、同期を維持したい2つのコレクションがあります。私のモデルオブジェクトには文字列のコレクションがあります:

public class Person {
    public int PersonId {get; set; }
    public string PersonName { get; set; }
    public List<string> PersonNicknames { get; set; }
}

このモデルオブジェクトを独自のViewModel(PersonViewModel)でラップします。ニックネームを編集できるようにするために、ニックネームも独自にラップしますNicknameViewModel。次に、PersonViewModelはObservableCollection<NicknameViewModel> NicknameViewModelCollection 、構築時に入力されるを公開します。

        foreach (string stringItem in _person.PersonNicknames)
        {
            var nicknameViewModel = new NicknameViewModel(stringItem);
            this.NicknameViewModelCollection.Add(nicknameViewModel);
        }

文字列が追加、削除、または変更で変更された場合PersonViewModel.NicknameViewModelCollection、モデルコレクションには反映されません(つまりPerson.Nicknames)。ユーザーが文字列アイテムを変更、編集、または削除するたびに、モデルコレクションを更新する必要があります。リンクされた回答がどのように機能するのか、またはそれをこの問題に適用する方法がわかりません。例は素晴らしいでしょう...私はここで途方に暮れています。

4

1 に答える 1

1

これは、あなたが探しているものに対する私の標準的な解決策です。contextなどのフィールドを持つ ViewModel タイプで動作するため、シナリオには少しオーバーヘッドがあります。とにかく、解決策は明らかになるはずです。コレクションは一般にOneWayToSourceを同期し、モデル コレクション自体が監視可能な場合はTwoWayを同期します。これは役に立ちますか?そうでない場合は、質問してください...

/// <summary>
/// Observable collection of ViewModels that pushes changes to a related collection of models
/// </summary>
/// <typeparam name="TViewModel">Type of ViewModels in collection</typeparam>
/// <typeparam name="TModel">Type of models in underlying collection</typeparam>

public class VmCollection<TViewModel, TModel> : ObservableCollection<TViewModel>
    where TViewModel : class, IViewModel, new()
    where TModel : class

{
    private readonly object _context;
    private readonly ICollection<TModel> _models;
    private bool _synchDisabled;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="models">List of models to synch with</param>
    /// <param name="context"></param>
    /// <param name="autoFetch">
    /// Determines whether the collection of ViewModels should be
    /// fetched from the model collection on construction
    /// </param>
    public VmCollection(ICollection<TModel> models, object context = null, bool autoFetch = true)
    {
        _models = models;
        _context = context;

        // Register change handling for synchronization
        // from ViewModels to Models
        CollectionChanged += ViewModelCollectionChanged;

        // If model collection is observable register change
        // handling for synchronization from Models to ViewModels
        if (models is ObservableCollection<TModel>)
        {
            var observableModels = models as ObservableCollection<TModel>;
            observableModels.CollectionChanged += ModelCollectionChanged;
        }


        // Fecth ViewModels
        if (autoFetch) FetchFromModels();
    }

    /// <summary>
    /// CollectionChanged event of the ViewModelCollection
    /// </summary>
    public override sealed event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add { base.CollectionChanged += value; }
        remove { base.CollectionChanged -= value; }
    }

    /// <summary>
    /// Load VM collection from model collection
    /// </summary>
    public void FetchFromModels()
    {
        // Deactivate change pushing
        _synchDisabled = true;

        // Clear collection
        Clear();

        // Create and add new VM for each model
        foreach (TModel model in _models)
            AddForModel(model);

        // Reactivate change pushing
        _synchDisabled = false;
    }

    private void ViewModelCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        // Return if synchronization is internally disabled
        if (_synchDisabled) return;

        // Disable synchronization
        _synchDisabled = true;

        // Synchronize collection of Models
        if (e.NewItems != null)
            foreach (var v in e.NewItems.OfType<IViewModel<TModel>>())
                v.AddModelTo(_models);
        if (e.OldItems != null)
            foreach (var v in e.OldItems.OfType<IViewModel<TModel>>())
                v.RemoveModelFrom(_models);


        //Enable synchronization
        _synchDisabled = false;
    }

    private void ModelCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (_synchDisabled) return;

        // Synchronize collection of ViewModels
        if (e.NewItems != null)
            foreach (TModel m in e.NewItems.OfType<TModel>()) this.AddIfNotNull(CreateViewModel(m));
        if (e.OldItems != null) foreach (TModel m in e.OldItems) this.RemoveIfContains(GetViewModelOfModel(m));
    }

    private TViewModel CreateViewModel(TModel model)
    {
        return ViewModelCache.Get<TViewModel>.ForExistingModel(model, _context);
    }

    private TViewModel GetViewModelOfModel(TModel model)
    {
        return Items.OfType<IViewModel<TModel>>().FirstOrDefault(v => v.IsViewModelOf(model)) as TViewModel;
    }

    /// <summary>
    /// Adds a new ViewModel for the specified Model instance
    /// </summary>
    /// <param name="model">Model to create ViewModel for</param>
    public void AddForModel(TModel model)
    {
        Add(CreateViewModel(model));
    }

    /// <summary>
    /// Adds a new ViewModel with a new model instance of the specified type,
    /// which is the ModelType or derived from the Model type
    /// </summary>
    /// <typeparam name="TSpecificModel">Type of Model to add ViewModel for</typeparam>
    public void AddNew<TSpecificModel>() where TSpecificModel : TModel, new()
    {
        var m = new TSpecificModel();
        Add(CreateViewModel(m));
    }
}
于 2013-01-28T08:08:18.900 に答える