如何手动处理WPF DataGrid的更新?

时间:2017-02-16 22:46:24

标签: c# wpf datagrid

我的DataGrid的项目是IList。更新IList的唯一方法是通过类所属的方法。

class SomeObject
{
    public ReadOnlyCollection<SomeType> Items { get; }

    public void AddItem(SomeType someType);

    public event Action<SomeType> ItemAdded;
}

列表本身是一个只读集合,不能直接更新 - 哇,它绝对不是一个ObservableCollection。有没有一种方法可以绑定到DataGrid用于显示目的,但是使用某种类型的绑定/ datagrid挂钩来处理对项目的创建,更新和删除?

2 个答案:

答案 0 :(得分:1)

您可以将ItemsSource的{​​{1}}属性绑定到任何返回DataGrid的公共属性,其中包含IEnumerable属性。你不能绑定到字段,所以如果你打算绑定它,你应该使IList<T>属性:

Items

但是,为了能够在运行时动态地向源集合添加项目并使新项目自动显示在DataGrid中,源集合必须实现public IList<SomeType> Items { get; private set; } 接口。只有INotifyCollectionChanged类在.NET Framework中执行此操作。 ObservableCollection<T>没有。

List<T>不是只读集合,因为它有一个Add方法:https://msdn.microsoft.com/en-us/library/system.collections.ilist.add%28v=vs.110%29.aspx。所以我猜你也可以使用IList<T>

修改

如果你真的想要手动补充ObservableCollection<T>&#34;&#34;您可以在视图的代码隐藏中订阅对象的DataGrid事件,并使用ItemAdded的{​​{1}}方法:

UpdateTarget()

或者你可以重置BindingExpression属性:

someObject.ItemAdded += (se, ee) => 
{
    var be = BindingOperations.GetBindingExpression(theDataGrid, DataGrid.ItemsSourceProperty);
    if (be != null)
        be.UpdateTarget();

};

编辑2:

  

我的问题是我需要一种可靠的方法来拦截网格的出站绑定机制,这样我就可以在添加新行时调用AddItem()。我已经尝试过使用IBindingList来查看我是否可以使用它,但是它还没有完全消失。

如果您将ItemsSource的{​​{1}}属性绑定到someObject.ItemAdded += (se, ee) => { theDataGrid.ItemsSource = someObject.Items; }; ,则可以处理此集合的ItemsSource事件:

DataGrid

ObservableCollection<SomeType>将新项目添加到源集合时,将引发此事件。

答案 1 :(得分:1)

为您的集合创建一个实现IBindingList和ICancelAddNew的代理。有了这两个你可以&#34;拦截&#34;调用添加新项目并删除现有项目。添加新项时会调用AddNew()方法,删除项时会调用Remove / RemoveAt。您可以调用为此目的设计的API方法,而不是直接修改集合。以下是所需的最小实现。请注意以下几点:

  1. 新项目不会立即添加到集合中 - 暂时存储在_newItem字段中

  2. 如果在编辑新项目时遇到转义,则先取消取消,然后调用EndNew

  3. 假设&#39;项目&#39;是一个可观察的集合,触发相应的ListChanged事件的事件

  4. 此技术并未提供拦截对现有项目属性所做编辑的方法

  5. ...

    class SomeTypeBindingList : IBindingList, ICancelAddNew
    {
        public SomeTypeBindingList(SomeObject someObject)
        {
            _someObject = someObject;
    
            var observableCollection = _someObject.Items as ObservableCollection<SomeType>;
            if (observableCollection != null)
                observableCollection.CollectionChanged += ObservableCollectionOnCollectionChanged;
        }
    
        public IEnumerator GetEnumerator()
        {
            return new SomeTypeEnumerator(this);
        }
    
        public int Count => _someObject.Items.Count + (_newItem == null ? 0 : 1);
    
        public object SyncRoot { get; } = new object();
    
        public bool IsSynchronized { get; } = false;
    
        public bool Contains(object value)
        {
            return IndexOf(value) != -1;
        }
    
        public int IndexOf(object value)
        {
            if (ReferenceEquals(value, _newItem))
                return _someObject.Items.Count;
    
            return _someObject.Items.IndexOf((SomeType)value);
        }
    
        public void Remove(object value)
        {
            var someType = (SomeType)value;
            _someObject.RemoveItem(someType);
        }
    
        public void RemoveAt(int index)
        {
            var someType = _someObject.Items[index];
            _someObject.RemoveItem(someType);
        }
    
        public object this[int index]
        {
            get
            {
                if (index >= _someObject.Items.Count)
                {
                    if(_newItem == null)
                        throw new IndexOutOfRangeException();
    
                    return _newItem;
                }
    
                return _someObject.Items[index];
            }
            set
            {
                throw new NotImplementedException();
            }
        }
    
        public object AddNew()
        {
            _newItem = new SomeType();
    
            ListChanged?.Invoke(this, new ListChangedEventArgs(ListChangedType.ItemAdded, _someObject.Items.Count));
            return _newItem;
        }
    
        public void CancelNew(int itemIndex)
        {
            _newItem = null;
            ListChanged?.Invoke(this, new ListChangedEventArgs(ListChangedType.ItemDeleted, itemIndex));
        }
    
        public void EndNew(int itemIndex)
        {
            if (_newItem != null)
            {
                var someType = _newItem;
                _newItem = null;
                _someObject.AddItem(someType);
            }
        }
    
        private void ObservableCollectionOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Remove)
                Enumerable.Range(e.OldStartingIndex, e.OldItems.Count).ForEach(i => ListChanged?.Invoke(this, new ListChangedEventArgs(ListChangedType.ItemDeleted, i)));
            else if(e.Action == NotifyCollectionChangedAction.Add)
                Enumerable.Range(e.NewStartingIndex, e.NewItems.Count).ForEach(i => ListChanged?.Invoke(this, new ListChangedEventArgs(ListChangedType.ItemAdded, i)));
        }
    
        private readonly SomeObject _someObject;
        private SomeType _newItem;
    
        class SomeTypeEnumerator : IEnumerator
        {
            public SomeTypeEnumerator(SomeObject someObject)
            {
                _someObject = someObject;
                Reset();
            }
    
            public void Dispose()
            {
    
            }
    
            public bool MoveNext()
            {
                _index++;
                return _someObject.Items.Count < _index;
            }
    
            public void Reset()
            {
                _index = -1;
            }
    
            public object Current => _someObject.Items[_index];
    
            object IEnumerator.Current
            {
                get { return Current; }
            }
    
            private readonly SomeObject _someObject;
            private int _index;
        }
    }