WPF - Best way to remove an item from the ItemsSource

我们两清 提交于 2019-11-29 04:52:46

The ItemCollection returned by ItemsControl.Items won't allow you to call Remove directly, but it implements IEditableCollectionView and does allow you to call the Remove method in that interface.

This will only work if the collection view bound to ItemsSource implements IEditableCollectionView itself. The default collection view will for most mutable collections, although not for objects that implement ICollection but not IList.

IEditableCollectionView items = tabControl.Items; //Cast to interface
if (items.CanRemove)
{
    items.Remove(tabControl.SelectedItem);
}

OK, I found a solution...

  • If the ItemsSource is databound, I either raise an event (for use with code-behind) or invoke a command (for use with a ViewModel) to remove the item from the ItemsSource collection.

  • If it's not databound, I raise an event to prompt the user for confirmation, and I remove the container directly from Items

    public static readonly DependencyProperty CloseTabCommandProperty =
        DependencyProperty.Register(
            "CloseTabCommand",
            typeof(ICommand),
            typeof(TabDocumentContainer),
            new UIPropertyMetadata(null));
    
    public ICommand CloseTabCommand
    {
        get { return (ICommand)GetValue(CloseTabCommandProperty); }
        set { SetValue(CloseTabCommandProperty, value); }
    }
    
    public event EventHandler<RequestCloseTabEventArgs> RequestCloseTab;
    public event EventHandler<TabClosingEventArgs> TabClosing;
    
    internal void CloseTab(TabDocumentContainerItem tabDocumentContainerItem)
    {
        if (ItemsSource != null) // Databound
        {
            object item = ItemContainerGenerator.ItemFromContainer(tabDocumentContainerItem);
            if (item == null || item == DependencyProperty.UnsetValue)
            {
                return;
            }
            if (RequestCloseTab != null)
            {
                var args = new RequestCloseTabEventArgs(item);
                RequestCloseTab(this, args);
            }
            else if (CloseTabCommand != null)
            {
                if (CloseTabCommand.CanExecute(item))
                {
                    CloseTabCommand.Execute(item);
                }
            }
        }
        else // Not databound
        {
            if (TabClosing != null)
            {
                var args = new TabClosingEventArgs(tabDocumentContainerItem);
                TabClosing(this, args);
                if (args.Cancel)
                    return;
            }
            Items.Remove(tabDocumentContainerItem);
        }
    }
    
Kent Boogaart

As you've found, your ItemsControl doesn't have intrinsic knowledge of the items being bound - those types are provided by consumers of your control. And you can't modify the collection directly because it may be data-bound.

The trick is to ensure each item is wrapped by a custom class (item container) of your choosing. Your ItemsControl you can provide this in the GetContainerForItemOverride method.

From there, you can define properties on your custom item container that you then bind to in your default template. For example, you could have a property called State that changes between Docked, Floating, and Closed. Your template would use this property to determine how - and whether - to show the item.

So you will not actually be changing the underlying data source at all. Instead, you will change a control-specific layer on top of the underlying data items that give you the info you need to implement your control.

Design practice dictates that you should really know what your ItemsSource is and be able to remove it from there directly. The binding then automatically updates the view of course.

However, if you are absolutely intent on some sort of generic functionality for removal, casting your ItemsSource to ICollection or ICollection<T> and then calling Remove sounds like a better/more reliable way to go than using the dynamic features of .NET.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!