我的DataGrid的项目是IList。更新IList的唯一方法是通过类所属的方法。
class SomeObject
{
public ReadOnlyCollection<SomeType> Items { get; }
public void AddItem(SomeType someType);
public event Action<SomeType> ItemAdded;
}
列表本身是一个只读集合,不能直接更新 - 哇,它绝对不是一个ObservableCollection。有没有一种方法可以绑定到DataGrid用于显示目的,但是使用某种类型的绑定/ datagrid挂钩来处理对项目的创建,更新和删除?
答案 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方法,而不是直接修改集合。以下是所需的最小实现。请注意以下几点:
新项目不会立即添加到集合中 - 暂时存储在_newItem字段中
如果在编辑新项目时遇到转义,则先取消取消,然后调用EndNew
假设&#39;项目&#39;是一个可观察的集合,触发相应的ListChanged事件的事件
此技术并未提供拦截对现有项目属性所做编辑的方法
...
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;
}
}