C# 添加到绑定TabControl(mvvm)后获取新选项卡的父级

C# 添加到绑定TabControl(mvvm)后获取新选项卡的父级,c#,wpf,mvvm,tabcontrol,C#,Wpf,Mvvm,Tabcontrol,我正在使用以下指南向选项卡添加关闭按钮: 这已成为一个问题,因为事件使用添加选项卡的“父级”从tabcontrol中删除该选项卡。我正在使用mvvm绑定tab控件,因此显然没有设置parent属性,并且当事件试图从中删除时,为父属性提供了null引用异常 这是装订,这样你就知道了: <TabControl Name="tabControl" Margin="0,22,0.2,-5.2" ItemsSource="{Binding Tabs}" Background="#FF4C76B2"

我正在使用以下指南向选项卡添加关闭按钮:

这已成为一个问题,因为事件使用添加选项卡的“父级”从tabcontrol中删除该选项卡。我正在使用mvvm绑定tab控件,因此显然没有设置parent属性,并且当事件试图从中删除时,为父属性提供了null引用异常

这是装订,这样你就知道了:

<TabControl Name="tabControl" Margin="0,22,0.2,-5.2" ItemsSource="{Binding Tabs}" Background="#FF4C76B2"/>
以下是发生空引用的事件:

void button_close_Click(object sender, RoutedEventArgs e)
{
    ((TabControl)this.Parent).Items.Remove(this);
}
在我看来,有两种选择:

  • 尝试找到另一种方法来删除选项卡(不带父项) 财产)
  • 尝试找到一种方法以某种方式设置父属性(不能 如果直接执行,则会引发编译器错误)

    • 我觉得这听起来不像是MVVM。我们处理的是数据,而不是UI元素。我们使用的类集合包含满足某些要求所需的所有属性,数据将这些属性绑定到
      DataTemplate
      s中的UI控件。通过这种方式,我们通过向这些集合中添加数据项来添加UI控件,并让出色的WPF模板系统来处理UI

      例如,您有一个
      TabControl
      ,我们想从中添加或删除
      TabItem
      s。。。以适当的MVVM方式。首先,我们需要一组可以表示每个
      TabItem
      的项:

      public static DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<string>), typeof(TestView));
      
      public ObservableCollection<string> Items
      {
          get { return (ObservableCollection<string>)GetValue(ItemsProperty); }
          set { SetValue(ItemsProperty, value); }
      }
      
      我们将集合数据绑定到
      TabControl.ItemsSource
      属性,并将
      TabControl.ItemTemplate
      设置为名为
      ItemTemplate
      资源。现在我们来看一下:

      xmlns:System="clr-namespace:System;assembly=mscorlib"
      ...
      <DataTemplate x:Key="ItemTemplate" DataType="{x:Type System:String}">
          <TabItem Header="{Binding}" />
      </DataTemplate>
      
      注意,为了完整起见,我包含了
      System
      XML名称空间前缀,但您不需要它,因为
      DataType
      将是您自己的自定义类。您还需要更多的
      DataTemplate
      s。例如,如果您的自定义类有一个
      标题
      属性和一个
      内容
      属性,这是另一个自定义类,我们称之为
      内容
      ,它包含
      选项卡项.Content
      属性的所有属性,您可以执行以下操作:

      <DataTemplate x:Key="ItemTemplate" DataType="{x:Type YourPrefix:YourClass}">
          <TabItem Header="{Binding Header}" Content="{Binding Content}" />
      </DataTemplate> 
      <DataTemplate DataType="{x:Type YourPrefix:Content}">
          <YourPrefix:SomeUserControl DataContext="{Binding}" />
      </DataTemplate>
      
      因此,无论哪个视图模型有
      选项卡
      集合,都应该有一个
      AddTabCommand
      和一个
      CloseTabCommand
      ,用于在
      选项卡
      集合中添加和删除项。但是,为了让它正常工作,您的
      ClosableTab
      类应该是一个数据类,而不是一个UI控件类。如果是UI控件,请使用
      DataTemplate
      指定它


      您可以从MSDN上找到有关
      RelayCommand
      的信息。

      我绑定itemsSource的可观察集合是上面代码中的“选项卡”。至于只是从集合中删除,是的,这就是我最终要做的(尽管我不喜欢这样,我必须传递viewmodel的引用才能从中获取Tabs属性)
      xmlns:System="clr-namespace:System;assembly=mscorlib"
      ...
      <DataTemplate x:Key="ItemTemplate" DataType="{x:Type System:String}">
          <TabItem Header="{Binding}" />
      </DataTemplate>
      
      Items.Add("Tab 1");
      Items.Add("Tab 2");
      Items.Add("Tab 3");
      
      <DataTemplate x:Key="ItemTemplate" DataType="{x:Type YourPrefix:YourClass}">
          <TabItem Header="{Binding Header}" Content="{Binding Content}" />
      </DataTemplate> 
      <DataTemplate DataType="{x:Type YourPrefix:Content}">
          <YourPrefix:SomeUserControl DataContext="{Binding}" />
      </DataTemplate>
      
      <Button Content="Close Tab" Command="{Binding CloseTabCommand}" 
          CommandParameter="{Binding}" />
      
      ...
      
      public ICommand CloseTabCommand
      {
          get { return new ActionCommand(action => Items.Remove(action), 
              canExecute => canExecute != null && Items.Contains(canExecute)); }
      }