1

MVVM フレームワーク用に Caliburn.Micro を実装する現在作業中の Silverlight アプリケーションがあります。正常に動作していますが、バインディングの一部におかしい点があることに気付きました。私が持っているのは、アプリケーションのナビゲーションを処理する ShellViewModel と ShellView です。ShellViewModel には、アプリケーション用に読み込まれた ViewModel のリストがあります。ShellViewModel は Conductor を継承しているため、すべてのアクティブ化と非アクティブ化を処理できます。

また、Conductor から継承する BaseConductorViewModel という ViewModel 基本クラスのタイプもあります。これは、基本的にマスター/ディテール ビューである ViewModel 用です。これらの BaseConductorViewModel には、Items という BindableCollection があります。このコレクションを ListBox または他の ItemsControl にバインドするという考えです。

この ViewModel と関連付けられた View の子を作成すると、ListBox (この場合) は、ShellViewModel レベルで ActiveItem を変更したときにのみバインディングを更新することに気付きました。したがって、アプリケーションが最初にロードされ、このビューがデフォルトのアクティブ ビューである場合、リストには何も表示されません (このリストのデータを取得するために Ria サービスを呼び出しています)。ただし、ShellViewModel/ShellView の別の ViewModel をクリックしてから戻ると、リストに項目が表示されます。これは、リストへのアイテムの追加または削除にも適用されます。アクティブなビューを切り替えないと更新されません。これは私には非常に奇妙に思え、私が例外としてそれをバインドする方法を理解できないようです. アイテムを追加/削除するときに注意すべきもう1つのこと。Refresh メソッドを呼び出します。

ここで何が起こっているのか、誰にも考えがありますか? または、これをデバッグしようとする方法についてのアイデアはありますか?

前もって感謝します!

ここにShellViewModelがあります

public abstract class ShellViewModel<V,M>:Conductor<IViewModel<V, M>>.Collection.OneActive, IViewModelCatalogShell<V,M>
    where V:IView
    where M:IModel
{
    #region Properties/Members
    public ViewModelSelectedItemList<V, M> Catalog { get; set; }
    #endregion

    #region Constructors
    public ShellViewModel()
    {
        Catalog = new ViewModelSelectedItemList<V, M>();
    }
    #endregion

}

そして、これが BaseConductorViewModel です

  public abstract class BaseConductorViewModel<T,V,M>:Conductor<T>, IViewModel<V, M>
    where V:IView
    where M:IModel
{
    #region Properties/Members
    protected Guid _id=Guid.Empty;
    public Guid Id 
    { 
        get{return _id;}
        set
        {
            _id =value;
            NotifyOfPropertyChange("Id");
        }
    }

    protected string _name=string.Empty;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            NotifyOfPropertyChange("Name");
        }
    }

    public string TypeName
    {
        get
        {
            return this.GetType().FullName;
        }
    }

    protected string _description = string.Empty;
    public string Description
    {
        get { return _description; }
        protected set
        {
            _description = value;
            NotifyOfPropertyChange(() => Description);
        }
    }

    protected V _view;
    public V View
    {
        get { return _view; }
        set
        {
            _view = value;
            NotifyOfPropertyChange("View");
        }
    }

    protected M _model;
    public M Model
    {
        get { return _model; }
        set
        {
            _model = value;
            NotifyOfPropertyChange("Model");
        }
    }

    protected SelectedItemList<T> _items;
    public SelectedItemList<T> Items
    {
        get { return _items; }
        set
        {
            _items = value;
            NotifyOfPropertyChange(() => Items);
        }
    }

    protected Guid _lastModifiedBy = Guid.Empty;
    public Guid LastModifiedBy
    {
        get { return _lastModifiedBy; }
        set 
        { 
            _lastModifiedBy = value;
            NotifyOfPropertyChange("LastModifiedBy");
        }
    }

    protected DateTime _lastModifiedOn = DateTime.Today;
    public DateTime LastModifiedOn
    {
        get { return _lastModifiedOn; }
        set
        {
            _lastModifiedOn = value;
            NotifyOfPropertyChange("LastModifiedOn");
        }
    }

    protected string _imageSource = string.Empty;
    public string ImageSource
    {
        get { return _imageSource; }
        protected set
        {
            _imageSource = value;
            NotifyOfPropertyChange("ImageSource");
        }
    }
    #endregion

    #region Constructors
    public BaseConductorViewModel()
    {
        _items = new SelectedItemList<T>();
        Items.SelectItemChanged += new SelectedItemChangedEvent(Items_SelectItemChanged);
        Items.SelectedIndexChanged += new SelectedIndexChangedEvent(Items_SelectedIndexChanged);


        LoadData();
    }
    public BaseConductorViewModel(V view, M model)
        :this()
    {
        _items = new SelectedItemList<T>();
        View = view;
        Model = model;

        Items.SelectItemChanged += new SelectedItemChangedEvent(Items_SelectItemChanged);
        Items.SelectedIndexChanged += new SelectedIndexChangedEvent(Items_SelectedIndexChanged);

        LoadData();
    }
    #endregion

    #region Methods
    public abstract void LoadData();
    #endregion

    #region Event Handlers
    private void Items_SelectItemChanged()
    {
        ChangeActiveItem(Items.SelectedItem, true);
        OnActiveItemChanged();
    }
    private void Items_SelectedIndexChanged(int index)
    {
        ChangeActiveItem(Items.SelectedItem, true);
        OnActiveItemChanged();
    }
    #endregion
}

ViewModelSelectedItemList は、このクラスの型指定されたバージョンです

 public class SelectedItemList<T>:IObservableCollection<T>
{
    #region Properties/Members
    protected BindableCollection<T> _items = new BindableCollection<T>();

    protected bool _isReadOnly = false;

    protected bool _isNotifying = true;
    public bool IsNotifying
    {
        get
        {
            return _isNotifying;
        }
        set
        {
            _isNotifying = value;
        }
    }

    public int Count
    {
        get { return _items.Count; }
    }

    protected int _selectedIndex = -1;
    public int SelectedIndex
    {
        get { return _selectedIndex; }
        set
        {
            _selectedIndex = value;
            NotifyOfPropertyChange("SelectedIndex");
            FireSelectedIndexChangedEvent(_selectedIndex);
        }
    }

    public T SelectedItem
    {
        get
        { return _items[_selectedIndex]; }
        set
        {
            _selectedIndex = _items.IndexOf(value);
            NotifyOfPropertyChange("SelectedItem");
            FireSelectedItemChangedEvent();
        }
    }

    #endregion

    #region Events
    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    public event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
    public event SelectedIndexChangedEvent SelectedIndexChanged;
    public event SelectedItemChangedEvent SelectItemChanged;
    #endregion

    #region Constructors
    #endregion

    #region Methods
    public void AddRange(System.Collections.Generic.IEnumerable<T> items)
    {
        if (!_isReadOnly)
        {
            foreach (T item in items)
            {
                _items.Add(item);
            }

            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count");  
            }
        }
    }
    public void RemoveRange(System.Collections.Generic.IEnumerable<T> items)
    {
        if (!_isReadOnly)
        {
            foreach (T item in items)
            {
                _items.Remove(item);
            }
            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count");  
            }
        }
    }

    public int IndexOf(T item)
    {
        return _items.IndexOf(item);
    }
    public void Insert(int index, T item)
    {
        if (!_isReadOnly)
        {
            _items.Insert(index, item);
            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count");  
            }
        }
    }
    public void RemoveAt(int index)
    {
        if (!_isReadOnly)
        {
            _items.RemoveAt(index);
            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count"); 
            } 
        }
    }

    public T this[int index]
    {
        get
        {
            return _items[index];
        }
        set
        {
            _items[index] = value;
        }
    }

    public void Add(T item)
    {
        if (!_isReadOnly)
        {
            _items.Add(item);
            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count");
                _items.Refresh();
            }

            if (_items.Count == 1)
            {
                SelectedIndex = 0;
            }
        }
    }
    public bool Remove(T item)
    {
        if (!_isReadOnly)
        { 
            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count");
            }
            return _items.Remove(item);
        }
        else
        {
            return false;
        }
    }

    public void Clear()
    {
        _items.Clear();
    }
    public bool Contains(T item)
    {
        return _items.Contains(item);
    }
    public void CopyTo(T[] array, int arrayIndex)
    {
        if (!_isReadOnly)
        {
            _items.CopyTo(array, arrayIndex);
            if (_isNotifying)
            {
                NotifyOfPropertyChange("Count");  
            }
        }
    }    

    public bool IsReadOnly
    {
        get { return _isReadOnly; }
    }
    public void Lock()
    {
        _isReadOnly = true;
    }
    public void Unlock()
    {
        _isReadOnly = false;
    }

    public System.Collections.Generic.IEnumerator<T> GetEnumerator()
    {
        return _items.GetEnumerator();
    }
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    public void NotifyOfPropertyChange(string propertyName)
    {
        FirePropertyChangedEvent(propertyName);
    }
    public void Refresh()
    {
        _items.Refresh();
    }

    #region Helper Methods
    protected void FirePropertyChangedEvent(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }

    }
    protected void FireCollectionChangedEvent(NotifyCollectionChangedAction action)
    {
        if (CollectionChanged != null)
        {
            CollectionChanged(this, new System.Collections.Specialized.NotifyCollectionChangedEventArgs(action));
        }
    }
    protected void FireSelectedIndexChangedEvent(int index)
    {
        if (SelectedIndexChanged != null)
        {
            SelectedIndexChanged(index);
        }
    }
    protected void FireSelectedItemChangedEvent()
    {
        if (SelectItemChanged != null)
        {
            SelectItemChanged();
        }
    }
    #endregion

    #endregion


}
4

1 に答える 1

0

あなたが問題を抱えているかどうかは、ドキュメントから、これと関係があるかどうかわからない:

IConductorのすべてのOOTB実装はScreenから継承するため、ライフサイクルもあり、ライフサイクルは実行しているアイテムにカスケードされます。したがって、コンダクターが非アクティブ化されると、そのActiveItemも非アクティブ化されます。コンダクターを閉じようとすると、コンダクターが行うすべてのアイテムを閉じることができる場合にのみ、コンダクターを閉じることができます。これは非常に強力な機能であることがわかりました。これについて、開発者を頻繁につまずかせることに気付いた1つの側面があります。それ自体がアクティブではないコンダクター内のアイテムをアクティブ化した場合、そのアイテムは、コンダクターがアクティブ化されるまで実際にはアクティブ化されません。これはあなたがそれについて考えるとき理にかなっていますが、時々髪を引っ張る原因となる可能性があります。

編集:私はあなたがやろうとしていることを理解していると思いますが、いくつか質問があります:

  1. あなたShellViewModelConductor<IViewModel<V,M>>.Collection.OneActive、いつカタログがアクティブになりますか?カタログをアイテムに追加してからアクティブ化することをお勧めします。
  2. を使用するBaseConductorViewModelと、Screenから継承するConductorから継承し、バインドされたときにビューへの参照を取得します。追加するViewプロパティの目的がわかりません。
  3. CMは選択したアイテムの設定を処理できます。したがって、ItemsControlがあるマスター詳細状況の場合、CMはSelectedItemを設定し、そこから詳細を入力できます。
于 2011-09-16T23:20:25.593 に答える