0

バックグラウンド:

MVVMパターンに厳密に従って、WPFアプリケーションを作成しています。さまざまなデータベースに接続するための汎用インターフェイスとして BaseRepository クラスがあり (EF はオプションではありません)、すべて正常に動作します。これは単なる技術的な質問です。

NotifyingCollection というラップされた ObservableCollection を使用して、IEditableObject の ItemEndEdit イベントをサブスクライブします (私の ViewModelBase エンティティ ラッパーは INotifyPropertyChanged および IEditableObject メンバーを実装しています)。

提供されているコード サンプルは、WPF DataGrid 内のアイテムの編集時に ReadAll メソッドが呼び出されると、" 'EditItem' はこのビューには許可されていません" という例外をスローします。ただし、メソッド内の行をコメントアウトされた部分に置き換えると、完全に機能します!

質問:

つまり、コレクションの IEnumerable バージョンを返す代わりに、Linq.Enumerable.Where 拡張メソッドを中継すると、カスタム コレクションから機能が削除されるように見えます。それらが両方とも IEnumerable である場合、なぜそれが起こるのでしょうか?

コードサンプル:

namespace MyCompany.Common.Abstracts
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Data.Common;
    using System.Diagnostics;
    using System.Linq;
    using System.Linq.Expressions;
    using MyCompany.Common.Extensions;
    using MyCompany.Common.Utilities;


    public abstract class BaseRepository<TEntity> : IDisposable where TEntity : ViewModelBase
    {
        protected BaseRepository()
        {
            this.EntitySet = new NotifyingCollection<TEntity>();
            this.EntitySet.ItemEndEdit += new ViewModelBase.ItemEndEditEventHandler(ItemEndEdit);
            this.EntitySet.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);
        }

        protected abstract NotifyingCollection<TEntity> EntitySet { get; set; }

        protected virtual void PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Debug.WriteLine(String.Format("Modify '{0}'", e.PropertyName), "PropertyChanged");
        }

        protected virtual void ItemEndEdit(IEditableObject sender)
        {
            this.Update(sender as TEntity);
        }

        protected virtual void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            var collection = (e.Action == NotifyCollectionChangedAction.Remove) ?
                e.OldItems : e.NewItems;

            foreach (TEntity entity in collection)
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        entity.PropertyChanged += this.PropertyChanged;
                        this.Create(entity);
                        break;

                    case NotifyCollectionChangedAction.Remove:
                        entity.PropertyChanged -= this.PropertyChanged;
                        this.Delete(entity);
                        break;

                    default:
                        Debug.WriteLine(String.Format("{0} '{1}'", e.Action.ToString(), entity.DisplayName), "CollectionChanged");
                        break;
                }
            }
        }

        public virtual bool Create(TEntity entity)
        {
            Debug.WriteLine(String.Format("Create '{0}'", entity.DisplayName), "CollectionChanged");
            return true;
        }

        public virtual IEnumerable<TEntity> Read(Expression<Func<TEntity, bool>> filter)
        {
            return this.EntitySet.Where(filter.Compile());
        }

        public virtual IEnumerable<TEntity> ReadAll()
        {
            return this.Read(x => true);
            //return this.EntitySet;
        }

        public virtual bool Update(TEntity entity)
        {
            Debug.WriteLine(String.Format("Update '{0}'", entity.DisplayName), "ItemEndEdit");
            return true;
        }

        public virtual bool Delete(TEntity entity)
        {
            Debug.WriteLine(String.Format("Delete '{0}'", entity.DisplayName), "CollectionChanged");
            return true;
        }

        public virtual IEnumerable<TColumn> GetColumn<TColumn>(string columnName)
        {
            var lookupTable = this.Read(x => x != null);

            List<TColumn> column = new List<TColumn>();
            foreach (TEntity record in lookupTable)
            {
                column.Add(record.GetPropValue<TColumn>(columnName));
            }
            var result = column.Distinct();

            foreach (TColumn element in result)
            {
                yield return element;
            }
        }

        public abstract int Commit();

        public abstract DbTransaction BeginTransaction();

        public abstract void Dispose();
    }
}
4

2 に答える 2

5

MichaelLPerry のブログから: ObservableCollection の使用中によくある間違い

ObservableCollection は必須です。Linq は宣言的です。この 2 つは、追加の支援なしでは一緒に使用できません。

命令型コードは、何かに対して明示的に作用します。ObservableCollection を使用する場合は、Add、Remove、およびその他のメソッドを明示的に呼び出してコレクションを変更します。これらのアクションをいつ、どのように実行するかを正確に決定する必要があります。

宣言型コードは暗黙的に何かを生成します。linq を使用する場合、コレクションがどのように表示されるか、どのようにフィルター処理、マップ、および変換されるかを宣言します。コレクションを明示的に変更しません。

これら 2 つのパラダイムは混在しません。ObservableCollection で linq を使用すると、監視できなくなります。このギャップを埋める Bindable Linq のようなオープンソース プロジェクトがあります。しかし、その特別な助けがなければ、人々は物事がうまくいかないときに驚くことがよくあります.

于 2013-06-27T16:00:00.760 に答える