【问题标题】:Getting parent of new tab after adding to bound TabControl (mvvm)添加到绑定的 TabControl (mvvm) 后获取新选项卡的父级
【发布时间】:2014-01-27 04:54:46
【问题描述】:

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

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

这已成为一个问题,因为该事件使用添加的选项卡的“父级”从选项卡控件中删除该选项卡。我正在使用 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);
}

在我看来,有两种选择:

  • 尝试寻找另一种方法来删除选项卡(没有父 财产)
  • 尝试找到一种方法来以某种方式设置父属性(不能 直接完成,它会引发编译器错误)

【问题讨论】:

    标签: c# wpf mvvm tabcontrol


    【解决方案1】:

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

    例如,您有一个 TabControl,我们希望以适当的 MVVM 方式从...中添加或删除 TabItems。首先,我们需要一个可以代表每个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 中敲了这个,为了简单起见,我只是使用strings 的集合。您需要创建一个类,其中包含整个TabItem 内容所需的所有数据。接下来我们看看TabControl

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

    我们将集合数据绑定到TabControl.ItemsSource 属性,并将TabControl.ItemTemplate 设置为名为@9​​87654337@ 的Resource。现在让我们看看:

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

    DataTemplate 定义了我们收藏中每件商品的外观。为简单起见,我们的strings 只是绑定到TabItem.Header 属性的数据。这意味着对于我们添加到集合中的每个项目,我们现在将获得一个新的TabItem,其Header 属性设置为string 的值:

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

    请注意,为了完整性,我包含了 System XML 命名空间前缀,但您不需要它,因为您的 DataType 将是您自己的自定义类。你也需要更多DataTemplates。例如,如果您的自定义类有一个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>
    

    所以这会给你TabItems 和Headers 集和来自SomeUserControlContent,你可以设计。你不需要使用UserControls,你可以在DataTemplate中添加更多的UI控件。但是您需要在某处添加更多控件...以及更多类和属性,始终记住正确实现基本的INotifyPropertyChanged interface

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


    更新>>>

    您的事件处理仍然不是那么 MVVM...您不需要在任何地方传递任何视图模型的引用。 MVVM 方式是在视图模型中使用命令。特别是,您应该调查RelayCommand。我有我自己的版本,但是这些命令使我们能够使用视图模型中的方法或内联 delegates(其中 actioncanExecute 在此示例中为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 和一个CloseTabCommand,它们可以在Tabs 集合中添加和删除项目。但要明确一点,要使其正常工作,您的 ClosableTab 类应该是数据类而不是 UI 控件类。如果是 UI 控件,请使用 DataTemplate 指定它。

    您可以在 MSDN 上的 this article 中找到有关 RelayCommand 的信息。

    【讨论】:

    • 我绑定 itemsSource 的 Observable 集合在上面的代码中是“Tabs”。至于只是从集合中删除,是的,这就是我最终要做的(尽管我不喜欢我必须传递我的视图模型的引用才能从中获取 Tabs 属性)
    猜你喜欢
    • 1970-01-01
    • 2017-04-22
    • 1970-01-01
    • 2011-03-28
    • 2018-08-27
    • 1970-01-01
    • 2018-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多