MVVM 集合的ViewModel

下面分享一个自己在工作中实际用到的关于集合处理的ViewModel。
    我们都知道,WPF中,有关于Combobox、List以及DataGrid等等的控件,其属性DataSource基本上都会与ObservableCollection<T>绑定。下面给出一个我自己的解决方案,以供参考。
    主要实现的功能有:提供数据源、双击、选项改变、添加数据项、移除数据项等

UML
 接口    ICollectionViewModel<T>

属性:
接口中的PageViewModel是分页的实现,此篇不分析和提供该类的实现方式!

Collection是对外提供的集合类
DoubleClickCommand是当双击选项时触发的命令
SelectedIndex是选中的索引
SelectedItem是选中的项
SelectedIsNull表示选中项是否为空

方法:
Add(T item)表示向集合中添加项
Clear():表示清空集合
GetIndex(Func<T, bool> predicate):表示根据条件获取该项在集合中所在的索引值
GetItem(Func<T, bool> predicate):根据条件获取项
Remove(T item):移除某项
RemoveAt(int index):移除指定索引项

事件:
CollectionChanged:参考ObservableCollection<T>中的CollectionChanged
DoubleClick:双击命令触发的事件
SelectedCheanged:选中项发生改变


 实现类  CollectionViewModel




实现代码:
   接口实现代码

/// <summary>
    /// Collection ViewModel Interface.
    /// </summary>
    /// <typeparam name="T">
    /// </typeparam>
    public interface ICollectionViewModel<T>
    {
        /// <summary>
        /// 选中项发生改变.
        /// </summary>
        event EventHandler SelectedChanged;
        /// <summary>
        /// 双击项
        /// </summary>
        event EventHandler DoubleClick;
        /// <summary>
        /// 集合改变.
        /// </summary>
        event NotifyCollectionChangedEventHandler CollectionChanged;
        /// <summary>
        /// 双击命令.
        /// </summary>
        ICommand DoubleClickCommand { get; }
        /// <summary>
        /// 数据源.
        /// </summary>
        ReadOnlyObservableCollection<T> Collection { get; }
        /// <summary>
        /// 选中项.
        /// </summary>
        T SelectedItem { get; set; }
        /// <summary>
        /// 选中项索引.
        /// </summary>
        int SelectedIndex { get; set; }
        /// <summary>
        /// 选中项是否为空.
        /// </summary>
        bool SelectedIsNull { get; }
        /// <summary>
        /// 根据条件获取索引.
        /// </summary>
        /// <param name="predicate">
        /// The predicate.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>
        int GetIndex(Func<T, bool> predicate);
        /// <summary>
        /// 根据条件获取项.
        /// </summary>
        /// <param name="predicate">
        /// The predicate.
        /// </param>
        /// <returns>
        /// The <see cref="T"/>.
        /// </returns>
        T GetItem(Func<T, bool> predicate);
        /// <summary>
        /// 添加项.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        void Add(T item);
        /// <summary>
        /// 清空集合.
        /// </summary>
        void Clear();
        /// <summary>
        /// 移除项.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        void Remove(T item);
        /// <summary>
        /// 移除制定索引项.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        void RemoveAt(int index);
        /// <summary>
        /// 转换为List.
        /// </summary>
        /// <returns>
        /// The <see>
        /// <cref>IList</cref>
        /// </see>
        /// .
        /// </returns>
        IList<T> ToList();
    }

    

    类实现代码

  
 /// <summary>
    /// The Collection ViewModel实现.
    /// </summary>
    /// <typeparam name="T">
    /// <tag>泛型</tag>
    /// </typeparam>
    public class CollectionViewModel<T> : ViewModelBase, ICollectionViewModel<T>
    {
        /// <summary>
        /// The seletected item.
        /// </summary>
        private T seletectedItem;
        /// <summary>
        /// The selected index.
        /// </summary>
        private int selectedIndex;
        /// <summary>
        /// Initializes a new instance of the <see cref="CollectionViewModel{T}"/> class.
        /// </summary>
        public CollectionViewModel()
        {
            this.DoubleClickCommand = new RelayCommand(
                () =>
            {
                if (DoubleClick != null)
                {
                    DoubleClick(this, new EventArgs());
                }
            });
            this.ListCollection = new ObservableCollection<T>();
            this.Collection = new ReadOnlyObservableCollection<T>(this.ListCollection);
            this.ListCollection.CollectionChanged += (o, e) => this.OnCollectionChanged(e);
        }
        /// <summary>
        /// The selected changed.
        /// </summary>
        public event EventHandler SelectedChanged;
        /// <summary>
        /// The double click.
        /// </summary>
        public event EventHandler DoubleClick;
        /// <summary>
        /// The collection changed.
        /// </summary>
        public event NotifyCollectionChangedEventHandler CollectionChanged;
        /// <summary>
        /// Gets the double click command.
        /// </summary>
        public ICommand DoubleClickCommand { get; private set; }
        /// <summary>
        /// Gets or sets the page view model.
        /// </summary>
        public IListPageViewModel PageViewModel { get; set; }
        /// <summary>
        /// Gets a value indicating whether selected is null.
        /// </summary>
        public bool SelectedIsNull
        {
            get
            {
                return null == this.SelectedItem;
            }
        }
        /// <summary>
        /// Gets or sets the selected index.
        /// </summary>
        public int SelectedIndex
        {
            get
            {
                return this.selectedIndex;
            }
            set
            {
                this.selectedIndex = value;
                this.RaisePropertyChanged("SelectedIndex");
            }
        }
        /// <summary>
        /// Gets or sets the selected item.
        /// </summary>
        public T SelectedItem
        {
            get
            {
                return this.seletectedItem;
            }
            set
            {
                this.seletectedItem = value;
                if (!this.SelectedIsNull && this.SelectedChanged != null)
                {
                    this.SelectedChanged(this, new EventArgs());
                }
                this.RaisePropertyChanged("SelectedItem");
            }
        }
        /// <summary>
        /// Gets the collection.
        /// </summary>
        public ReadOnlyObservableCollection<T> Collection { get; private set; }
        /// <summary>
        /// Gets the list collection.
        /// </summary>
        protected ObservableCollection<T> ListCollection { get; private set; }
        /// <summary>
        /// The add.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        public void Add(T item)
        {
            this.ListCollection.Add(item);
           
        }
        /// <summary>
        /// The clear.
        /// </summary>
        public void Clear()
        {
            this.ListCollection.Clear();
        }
        /// <summary>
        /// The get index.
        /// </summary>
        /// <param name="predicate">
        /// The predicate.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>
        /// <exception cref="NullReferenceException">
        /// </exception>
        public int GetIndex(Func<T, bool> predicate)
        {
            if (predicate == null)
            {
                throw new NullReferenceException("predicate is null");
            }
            var index = this.ListCollection.Where(predicate)
                .Select(m => this.ListCollection.IndexOf(m))
                .SingleOrDefault();
            return index;
        }
        /// <summary>
        /// The get item.
        /// </summary>
        /// <param name="predicate">
        /// The predicate.
        /// </param>
        /// <returns>
        /// The <see cref="T"/>.
        /// </returns>
        /// <exception cref="NullReferenceException">
        /// </exception>
        public T GetItem(Func<T, bool> predicate)
        {
            if (predicate == null)
            {
                throw new NullReferenceException("predicate is null");
            }
            var obj = this.ListCollection.SingleOrDefault(predicate);
            return obj;
        }
        /// <summary>
        /// The remove at.
        /// </summary>
        /// <param name="index">
        /// The index.
        /// </param>
        public void RemoveAt(int index)
        {
            this.ListCollection.RemoveAt(index);
        }
        /// <summary>
        /// The to list.
        /// </summary>
        /// <returns>
        /// The <see cref="IList{T}"/>.
        /// </returns>
        public IList<T> ToList()
        {
            return this.ListCollection.ToList();
        }
        /// <summary>
        /// The remove.
        /// </summary>
        /// <param name="item">
        /// The item.
        /// </param>
        public void Remove(T item)
        {
            this.ListCollection.Remove(item);
        }
        /// <summary>
        /// The on collection changed.
        /// </summary>
        /// <param name="e">
        /// The e.
        /// </param>
        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
        {
            var handler = this.CollectionChanged;
            if (handler != null)
            {
                handler(this, e);
            }
        }
    }





通过实现代码可以看出,CollectionViewModel<T>主要提供了两个集合
 public ReadOnlyObservableCollection<T> Collection { get; private set; }
protected ObservableCollection<T> ListCollection { get; private set; } 

对于Collection,它是对外只读集合,也就是说,所以对集合的操作都必须通过CollectionViewModel类来实现,这样,我们就通过CollectionViewModel控制了集合的修改,防止了外部修改集合。

使用:
    Combobox:

   
<ComboBox 
     DataContext="{Binding FactoryRegulationCollectionVm, Mode=OneWay}"
      ItemsSource="{Binding Collection}"
     SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
     DisplayMemberPath="FactoryRegulationName" />



    DataGrid:此处的DataGrid提供了双击选项的功能
   
<DataGrid 
     Grid.Row="2" BorderBrush="#D24726" BorderThickness="1"
     DataContext="{Binding ImageinfoCollectionViewModel}"
     ItemsSource="{Binding Collection}"                   
     SelectedItem="{Binding SelectedItem,Mode=TwoWay}" 
     IsReadOnly="True" CanUserSortColumns="False"           HorizontalAlignment="Center"
                    AutoGenerateColumns="False"  
        > 
            <i:Interaction.Triggers>
                <!--双击事件绑定到命令-->
                <i:EventTrigger EventName="PreviewMouseDoubleClick">
                    <i:InvokeCommandAction
                        Command="{Binding DoubleClickCommand}"></i:InvokeCommandAction>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            <DataGrid.Columns>
                <DataGridTextColumn Header="{DynamicResource lang_SerialNumber}" Binding="{Binding rowID}" />
            </DataGrid.Columns>
        </DataGrid>



未解决的问题:
    1.  多选的问题,就是在DataGrid中,选中多个项,暂时没有想到比较好的解决方案。
    2.  其他未使用到的。上面给出的处理方案都是在实际工作中遇到的,也许还有其他需要解决的,但是暂时还未遇到。


注:
    1.  本人的ViewModel主要依靠的框架是  MVVM Light  ,感兴趣的可以自行百度
    2.  本人 QQ:351157970,  欢迎交流,一起讨论工作中遇到的问题
    3.  Demo代码:CollectionViewModel


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章