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


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