代码之家  ›  专栏  ›  技术社区  ›  Thomas Levesque

wpf-从itemssource中移除项的最佳方法

  •  5
  • Thomas Levesque  · 技术社区  · 16 年前

    我在写一个习惯 ItemsControl (一个带选项卡的文档容器),当用户关闭它时,每个项(选项卡)都可以从UI中移除自己。但是,我不能直接从 ItemsControl.Items 集合,因为可以对项进行数据绑定。所以我必须把它从 ItemsSource 什么都可以( ICollection , DataTable , DataSourceProvider ……)

    在应用程序的上下文中,我知道 项目源 是的,但我希望该控件更通用,以便稍后重用。

    因此,我正在寻找一种从数据源中删除项目的方法,而不知道它的类型。我可以用倒影,但感觉很脏…到目前为止,我提出的最佳解决方案是使用 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 回复  |  直到 10 年前
        1
  •  9
  •   Quartermeister    16 年前

    这个 ItemCollection 返回的 ItemsControl.Items 不允许直接调用remove,但它实现 IEditableCollectionView 并且允许您调用该接口中的remove方法。

    仅当集合视图绑定到 ItemsSource 器具 IEditableCollectionView(可编辑集合视图) 本身。默认集合视图将用于大多数可变集合,但不用于实现 ICollection 但不是 IList .

    IEditableCollectionView items = tabControl.Items; //Cast to interface
    if (items.CanRemove)
    {
        items.Remove(tabControl.SelectedItem);
    }
    
        2
  •  2
  •   Thomas Levesque    16 年前

    好吧,我找到了解决办法…

    • 如果 ItemsSource 是数据绑定的,我要么引发一个事件(用于代码隐藏),要么调用一个命令(用于ViewModel)从 项目源 收集。

    • 如果它不是数据绑定的,我会引发一个事件来提示用户进行确认,然后直接从 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);
          }
      }
      
        3
  •  -1
  •   Tim Cooper    14 年前

    正如你所发现的,你的 ItemsControl 不具备绑定项目的内在知识-这些类型由控件的消费者提供。您不能直接修改集合,因为它可能是数据绑定的。

    技巧是确保每个项目都由您选择的自定义类(项目容器)包装。你的 项目控制 您可以在 GetContainerForItemOverride 方法。

    从那里,您可以定义自定义项容器上的属性,然后在默认模板中绑定到这些属性。例如,可以有一个名为 State 两者之间的变化 Docked , Floating Closed . 您的模板将使用此属性来确定如何以及是否显示该项。

    因此,实际上您根本不会更改基础数据源。相反,您将在底层数据项的顶部更改一个特定于控件的层,这些数据项为您提供实现控件所需的信息。

        4
  •  -3
  •   Noldorin    16 年前

    设计实践要求您真正了解 ItemsSource 可以直接从那里移除。然后绑定会自动更新视图。

    但是,如果您绝对希望删除某种通用功能,则强制转换 项目源 ICollection ICollection<T> 然后打电话 Remove 听起来比使用.NET的动态特性更好/更可靠。