2014-01-08 55 views
2

我使用以下指南将关闭按钮,以我的标签后:获得新标签的父增加绑定的TabControl(MVVM)

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

这已成为一个问题,因为该事件使用添加选项卡的'父'从tabcontrol删除该选项卡。我使用mvvm绑定了选项卡控件,因此父项属性显然未被设置,并且在事件尝试从其中删除时为父项提供空引用异常。

这里的绑定,所以你的想法:

<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); 
} 

在我看来有两个选择:

  • 试图找到另一种方式来删除该选项卡(没有父母 财产)
  • 试图找到一种方法来设置父母的财产(这不能是 唐它直接引发编译器错误)

回答

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到一个名为ItemTemplateResource。让我们来看看现在:

xmlns:System="clr-namespace:System;assembly=mscorlib" 
... 
<DataTemplate x:Key="ItemTemplate" DataType="{x:Type System:String}"> 
    <TabItem Header="{Binding}" /> 
</DataTemplate> 

DataTemplate定义了我们收藏的每件将是什么样子。为了简单起见,我们的string只是数据绑定到TabItem.Header属性。这意味着,对于我们添加到集合中的每个项目,我们现在得到一个新的TabItemHeader属性设置为string的价值:我包括System XML命名空间前缀的完整性

Items.Add("Tab 1"); 
Items.Add("Tab 2"); 
Items.Add("Tab 3"); 

注,但您不需要这样做,因为您的DataType将是您自己的自定义课程。您还需要更多DataTemplate。例如,如果您的自定义类有一个Header属性和Content财产,这是另一种自定义的类,我们说叫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> 

所以这会给你TabItemHeader秒和Content来自SomeUserControl你可以设计。您不需要使用UserControl,您可以将更多UI控件添加到DataTemplate。但是您需要在某处添加更多控件...以及更多类和属性,并始终记住要正确实现必要的INotifyPropertyChanged interface

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


UPDATE >>>

你的事件处理还不是那么MVVM ......你不需要在任何地方通过任何视图模型的参考。 MVVM的方式是在视图模型中使用命令。特别是,您应该调查RelayCommand。我有我自己的版本,但这些命令使我们能够从数据绑定Button S和使用视图模型的方法或内嵌delegate S以外的UI控件执行操作(其中action在这个例子中canExecuteCommandParameter值):

<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和一个CloseTabCommand添加和删除Tabs集合中的项目。但要清楚,为了正常工作,你的ClosableTab类应该是一个数据类,而不是一个UI控制类。如果它是UI控件,请使用DataTemplate进行指定。

您可以在MSDN上找到有关this articleRelayCommand的信息。

+0

我绑定itemsSource的Observable集合是上面代码中的'Tabs'。 至于刚刚从集合中删除,这是我最终做的事情(虽然我不喜欢我必须通过我的viewmodel的引用来从它获取Tabs属性) – rcj