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

时间:2014-01-08 21:15:37

标签: c# wpf mvvm tabcontrol

我正在使用以下指南为我的标签添加一个关闭按钮:

http://www.codeproject.com/Articles/84213/How-to-add-a-Close-button-to-a-WPF-TabItem

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

这是绑定所以你明白了:

<TabControl Name="tabControl" Margin="0,22,0.2,-5.2" ItemsSource="{Binding Tabs}" Background="#FF4C76B2"/>

继续添加标签的地方。

private void AddTab(object tabName)
{
    ClosableTab newTab = new ClosableTab();
    newTab.Title = "title?";
    //newTab.Header = tabName;
    TextBox test = new TextBox();

    test.Text = "CONTENT (" + tabName + ") GOES HERE";
    newTab.Content = test;

    Tabs.Add(newTab);
    OnPropertyChanged("Tabs");
}

以下是发生空引用的事件:

void button_close_Click(object sender, RoutedEventArgs e)
{
    ((TabControl)this.Parent).Items.Remove(this);
}

我认为有两种选择:

  • 尝试找到另一种方法来删除标签(没有父标签) 属性)
  • 尝试找到一种方法以某种方式设置父属性(不可能 直接完成,它会抛出编译器错误)

1 个答案:

答案 0 :(得分:2)

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

例如,您有TabControl我们想要以适当的MVVM方式添加或删除TabItem。首先,我们需要一组可以代表每个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); }
}

我只是使用DependencyProperty,因为我在UserControl中将其敲了一下而我只是为了简单而使用了string的集合。您需要创建一个包含所有整个TabItem内容所需数据的类。接下来,让我们看看TabControl

<TabControl ItemsSource="{Binding Items}" ItemTemplate="{StaticResource ItemTemplate}" />

我们将数据绑定到TabControl.ItemsSource属性,然后将TabControl.ItemTemplate设置为名为Resource的{​​{1}}。我们现在看看:

ItemTemplate

xmlns:System="clr-namespace:System;assembly=mscorlib" ... <DataTemplate x:Key="ItemTemplate" DataType="{x:Type System:String}"> <TabItem Header="{Binding}" /> </DataTemplate> 定义了我们的集合中的每个项目的外观。为简单起见,我们的DataTemplate只是绑定到string属性的数据。这意味着,对于我们添加到集合中的每个项目,我们现在将获得一个新的TabItem.Header,其TabItem属性设置为Header的值:

string

请注意,为了完整性,我添加了Items.Add("Tab 1"); Items.Add("Tab 2"); Items.Add("Tab 3"); XML命名空间前缀,但您不需要这样做,因为您的System将是您自己的自定义类。您还需要更多DataType s。例如,如果您的自定义类具有DataTemplate属性和Header属性,这是另一个自定义类,那么假设名为Content,其中包含{{1}的所有属性属性,你可以这样做:

Content

因此,这会为您TabItem.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> 的设置和来自TabItem的{​​{1}},您可以设计它。您无需使用Header,只需向Content添加更多UI控件即可。但是你需要在某处添加更多控件...以及更多类和属性,始终记住正确实现基本INotifyPropertyChanged interface

最后,要以正确的MVVM方式回答您的问题...要删除SomeUserControl,您只需从集合中删除与该UserControl相关的项目。简单......或者如果你真的像你声称的那样使用MVVM就应该这样。非常值得学习MVVM,因为你很快就会看到好处。我会让你找到自己的教程,因为有很多选择。


更新&gt;&gt;&gt;

你的事件处理仍然不是MVVM ......你不需要在任何地方传递任何视图模型的引用。 MVVM方式是在视图模型中使用命令。特别是,您应该调查DataTemplate。我有自己的版本,但这些命令使我们能够使用视图模型中的方法或内联TabItem来执行来自数据绑定TabItem和其他UI控件的操作(其中RelayCommand和{此示例中的{1}}是Button值:

delegate

因此,无论您的action集合中的canExecute集合都应该有CommandParameter<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)); } } 添加和删除Tabs集合中的项目。但为了清楚起见,为了使其正常工作,您的AddTabCommand类应该是数据类而不是UI控件类。如果它是UI控件,请使用CloseTabCommand指定它。

您可以在MSDN上找到Tabs的{​​{1}}。