6

ItemsControlユーザーがタブを閉じると、各項目 (タブ) が UI から削除されるカスタム(タブ付きドキュメント コンテナー) を作成しています。ItemsControl.Itemsただし、アイテムがデータバインドされている可能性があるため、コレクションから直接削除することはできません。だから私はそれをから削除する必要がありItemsSourceます。これは何でもかまいません(、、ICollection... )。DataTableDataSourceProvider

私のアプリケーションのコンテキストでは、 の実際の型はわかっています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

4 に答える 4

12

ItemCollectionによって返されたではItemsControl.Items、Remove を直接呼び出すことはできませんが、実装されIEditableCollectionViewており、そのインターフェイスで Remove メソッドを呼び出すことができます。

これは、コレクション ビューがバインドされている場合にのみ機能しItemsSourceますIEditableCollectionView。既定のコレクション ビューは、ほとんどの可変コレクションに対応しますが、 を実装するオブジェクトには対応してICollectionいませんIList

IEditableCollectionView items = tabControl.Items; //Cast to interface
if (items.CanRemove)
{
    items.Remove(tabControl.SelectedItem);
}
于 2010-07-17T14:00:20.973 に答える
2

わかりました、解決策を見つけました...

  • がデータ バインドされている場合は、イベントを発生させるか (コード ビハインドで使用する場合)、コマンドを呼び出して (ViewModel で使用する場合)、コレクションItemsSourceからアイテムを削除します。ItemsSource

  • データバインドされていない場合は、イベントを発生させてユーザーに確認を求め、コンテナをコンテナから直接削除します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);
        }
    }
    
于 2010-07-17T14:15:31.070 に答える
-1

あなたが見つけたように、あなたItemsControlはバインドされているアイテムの本質的な知識を持っていません-それらのタイプはあなたのコントロールの消費者によって提供されます。また、データ バインドされている可能性があるため、コレクションを直接変更することはできません。

秘訣は、選択したカスタム クラス (アイテム コンテナー) によって各アイテムが確実にラップされるようにすることです。メソッドItemsControlでこれを提供できますGetContainerForItemOverride

そこから、カスタム アイテム コンテナーのプロパティを定義して、既定のテンプレートにバインドできます。たとえば、 、 、 の間で変化する という名前のプロパティを作成できStateます。テンプレートはこのプロパティを使用して、項目を表示する方法と表示するかどうかを決定します。DockedFloatingClosed

したがって、基になるデータ ソースを実際に変更することはまったくありません。代わりに、コントロールを実装するために必要な情報を提供する、基になるデータ項目の上にあるコントロール固有のレイヤーを変更します。

于 2010-07-17T13:15:52.103 に答える
-3

設計の実践では、自分が何であるかを本当に理解しItemsSource、そこから直接削除できるようにする必要があります。もちろん、バインディングは自動的にビューを更新します。

ただし、ある種の一般的な機能を削除することを完全に意図している場合は、.NET の動的機能を使用するよりも、にキャストItemsSourceICollectionたりICollection<T>、呼び出しRemoveたりする方が適切で信頼性の高い方法のように思えます。

于 2010-07-17T13:11:03.617 に答える