I'm writing a custom ItemsControl
(a tabbed document container), where each item (tab) can remove itself from the UI when the user closes it. However, I can't remove it directly from the ItemsControl.Items
collection, because the items can be databound. So I have to remove it from the ItemsSource
, which can be anything (ICollection
, DataTable
, DataSourceProvider
...).
In the context of my application, I know what the actual type of the ItemsSource
will be, but I want that control to be more generic so that I can reuse it later.
So I'm looking for a way to remove an item from a data source, without knowing its type. I could use reflection, but it feels dirty... So far the best solution I came up with is using 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());
}
}
But I'm not really happy with it, I'm sure there must be a better way. Any suggestions would be appreciated !
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);
}
}