我正在编写自定义ItemsControl
(标签式文档容器),其中每个项目(选项卡)可以在用户关闭UI时将其自身从UI中删除。但是,我无法直接从ItemsControl.Items
集合中删除它,因为这些项可以是数据绑定的。所以我必须将其从ItemsSource
中删除,这可以是任何内容(ICollection
,DataTable
,DataSourceProvider
...)。
在我的应用程序的上下文中,我知道ItemsSource
的实际类型是什么,但我希望该控件更通用,以便我以后可以重用它。
所以我正在寻找一种从数据源中删除项目的方法,而不知道它的类型。我可以使用反射,但感觉很脏......到目前为止,我提出的最佳解决方案是使用dynamic
:
internal void CloseTab(TabDocumentContainerItem tabDocumentContainerItem)
{
// TODO prompt user for confirmation (CancelEventHandler ?)
var item = ItemContainerGenerator.ItemFromContainer(tabDocumentContainerItem);
// TODO find a better way...
try
{
dynamic items = ItemsSource;
dynamic it = item;
items.Remove(it);
}
catch(RuntimeBinderException ex)
{
Trace.TraceError("Oops... " + ex.ToString());
}
}
但我对此并不满意,我相信一定有更好的方法。任何建议将不胜感激!
答案 0 :(得分:9)
ItemCollection
返回的ItemsControl.Items
将不允许您直接调用Remove,但它实现IEditableCollectionView
并允许您在该界面中调用Remove方法。
这仅在绑定到ItemsSource
的集合视图本身实现IEditableCollectionView
时才有效。默认集合视图适用于大多数可变集合,但不适用于实现ICollection
但不实现IList
的对象。
IEditableCollectionView items = tabControl.Items; //Cast to interface
if (items.CanRemove)
{
items.Remove(tabControl.SelectedItem);
}
答案 1 :(得分:2)
好的,我找到了解决方案......
如果ItemsSource
是数据绑定,我要么引发一个事件(用于代码隐藏),要么调用一个命令(用于ViewModel)从{{1}中删除该项目收集。
如果它不是数据绑定,我会举起一个事件来提示用户进行确认,我直接从ItemsSource
Items
答案 2 :(得分:-1)
正如您所发现的,您的ItemsControl
对绑定的项目没有内在的了解 - 这些类型由您的控件的消费者提供。并且您无法直接修改集合,因为它可能是数据绑定的。
诀窍是确保每个项目都由您选择的自定义类(项容器)包装。您ItemsControl
可以使用GetContainerForItemOverride
方法提供此内容。
从那里,您可以在自定义项容器上定义属性,然后在默认模板中将其绑定到该属性。例如,您可以在State
,Docked
和Floating
之间更改名为Closed
的属性。您的模板将使用此属性来确定如何以及是否显示该项目。
因此,您根本不会真正更改基础数据源。相反,您将在基础数据项之上更改特定于控件的图层,从而为您提供实现控件所需的信息。
答案 3 :(得分:-3)
设计实践要求您确实应该知道ItemsSource
是什么,并且能够直接从那里删除它。然后绑定会自动更新视图。
但是,如果您绝对想要删除某些通用功能,那么将ItemsSource
转换为ICollection
或ICollection<T>
,然后调用Remove
听起来更合适/比使用.NET的动态功能更可靠。