WPF - 从ItemsSource中删除项目的最佳方法

时间:2010-07-17 13:06:18

标签: wpf itemscontrol itemssource

我正在编写自定义ItemsControl(标签式文档容器),其中每个项目(选项卡)可以在用户关闭UI时将其自身从UI中删除。但是,我无法直接从ItemsControl.Items集合中删除它,因为这些项可以是数据绑定的。所以我必须将其从ItemsSource中删除,这可以是任何内容(ICollectionDataTableDataSourceProvider ...)。

在我的应用程序的上下文中,我知道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());
        }
    }

但我对此并不满意,我相信一定有更好的方法。任何建议将不胜感激!

4 个答案:

答案 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方法提供此内容。

从那里,您可以在自定义项容器上定义属性,然后在默认模板中将其绑定到该属性。例如,您可以在StateDockedFloating之间更改名为Closed的属性。您的模板将使用此属性来确定如何以及是否显示该项目。

因此,您根本不会真正更改基础数据源。相反,您将在基础数据项之上更改特定于控件的图层,从而为您提供实现控件所需的信息。

答案 3 :(得分:-3)

设计实践要求您确实应该知道ItemsSource是什么,并且能够直接从那里删除它。然后绑定会自动更新视图。

但是,如果您绝对想要删除某些通用功能,那么将ItemsSource转换为ICollectionICollection<T>,然后调用Remove听起来更合适/比使用.NET的动态功能更可靠。