silverlight - Caliburn Entity DataBinding 有趣

标签 silverlight data-binding mvvm caliburn.micro caliburn

我有一个我目前正在使用的 Silverlight 应用程序,它为其 MVVM 框架实现了 Caliburn.Micro。一切正常,但我注意到一些绑定(bind)中的一些有趣之处。我拥有的是处理应用程序导航的 ShellViewModel 和 ShellView。 ShellViewModel 有一个为应用程序加载的 ViewModel 的列表。 ShellViewModel 继承自 Conductor,因此它可以处理所有的激活和停用。

我还有一种 ViewModel 基类,称为 BaseConductorViewModel,它也继承自 Conductor。这适用于基本上是 Master-Detail View 的 ViewModel。对于这些 BaseConductorViewModels,我有一个名为 Items 的 BindableCollection。想法是将这个集合绑定(bind)到 ListBox 或其他 ItemsControl。

当我创建此 ViewModel 的子项和关联的 View 时,我注意到 ListBox(在这种情况下)仅在我更改 ShellViewModel 级别的 ActiveItem 时刷新绑定(bind)。因此,当应用程序最初加载并且此 View 是默认的事件 View 时,您不会在列表中看到任何内容(我正在调用 Ria 服务来获取此列表的数据)。但是,如果我单击 ShellViewModel/ShellView 上的另一个 ViewModel,然后单击返回,它将显示列表中的项目。这也适用于将项目添加到列表或删除它们。除非我切换事件 View ,否则它不会刷新。这对我来说似乎很奇怪,我似乎无法像我想的那样想办法让它绑定(bind)。还有一件事要注意,当我添加/删除项目时;我调用 Refresh 方法,目前我没有使用 NotifyOfPropertyChange 方法,尽管我之前确实尝试过相同的结果。

有人对这里可能发生的事情有任何想法吗?或者关于我如何尝试调试它的任何想法?

先感谢您!

这是 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


}

最佳答案

不确定您的问题是否与此有关,来自 docs :

Since all OOTB implementations of IConductor inherit from Screen it means that they too have a lifecycle and that lifecycle cascades to whatever items they are conducting. So, if a conductor is deactivated, it’s ActiveItem will be deactivated as well. If you try to close a conductor, it’s going to only be able to close if all of the items it conducts can close. This turns out to be a very powerful feature. There’s one aspect about this that I’ve noticed frequently trips up developers. If you activate an item in a conductor that is itself not active, that item won’t actually be activated until the conductor gets activated. This makes sense when you think about it, but can occasionally cause hair pulling.



编辑:
我想我明白你在做什么,不过有几个问题:
  • 您的 ShellViewModelConductor<IViewModel<V,M>>.Collection.OneActive , 什么时候是目录
    active ?我认为您想将目录添加到项目中,然后
    激活它。
  • BaseConductorViewModel , 它继承自 Conductor
    继承自 Screen,当它是
    边界。我不确定您添加的 View 属性是做什么用的。
  • CM 可以为您处理设置所选项目。所以对于大师
    有 ItemsControl 的详细情况,CM 将设置
    SelectedItem 并从中您可以填充详细信息。
  • 关于silverlight - Caliburn Entity DataBinding 有趣,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7450848/

    相关文章:

    c# - 如何在 Windows Phone 7 设备上拍摄位图图像并另存为 JPEG 图像文件?

    silverlight - 无论如何要更改 Silverlight 3 中 OpenFileDialog 的标题?

    android - View 属性的数据绑定(bind)错误

    wpf - OxyPlot 图表中的可绑定(bind)注释

    c# - 如何在 WPF 中将 ViewModels 对象数据绑定(bind)为 3DModels

    wpf - 如何从 ViewModel 更改 View 中的 VisualState?

    .net - 在 Windows Phone API 中反射 DLL (SIlverlight)

    android - ViewModel 方法名称约定

    mvvm - Xamarin Forms 和 TabGestureRecognizer 不会使用 Command 触发

    firebase - SwiftUI 和 MVVM : How to display data from Firebase/Firestore in View?