如何关闭MVVM Light中的TabItem

时间:2012-07-17 12:38:50

标签: silverlight events xaml binding mvvm

在我看来,我正在添加动态自定义TabItems(TextseiteTabItem)。使用属性DataContext,我为每个TabItem提供了一个可以使用的模型(填充值)。现在我添加了一个关闭命令到自定义TabItems但它不会工作。我无法将close命令发送到viewmodel。以上是我的尝试..

我的自定义TabItem:

<sdk:TabItem x:Class="PortfolioCreator.TextseiteTabItem" 
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
           mc:Ignorable="d"
           xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
           xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
           xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">

    <sdk:TabItem.Header>
        <StackPanel Orientation="Horizontal">
            <sdk:Label Content="{Binding Seitennummer, StringFormat='Seite {0}', Mode=TwoWay}"/>
            <Button Content="X"
                    Command="{Binding CloseTabCommand, Mode=TwoWay}"
                    DataContext="{Binding ElementName=TemplateTabControl}"
                    CommandParameter="{Binding SelectedItem, ElementName=TemplateTabControl}" />   
        </StackPanel>
    </sdk:TabItem.Header>

    <sdk:TabItem.Content>
        <Grid x:Name="LayoutRoot">
            ...
        </Grid>
    </sdk:TabItem.Content>
</sdk:TabItem>

在我的观点中:

...
<sdk:TabControl toolkit:DockPanel.Dock="Bottom" ItemsSource="{Binding Tabs}" x:Name="TemplateTabControl"/>
...

在我的ViewModel中:

public class PortfolioViewModel : ViewModelBase
{
    public ObservableCollection<TabItem> Tabs { get; set; }

    public RelayCommand<TabItem> CloseTabCommand
    {
        get;
        private set;
    }

    public PortfolioViewModel()
    {
        CloseTabCommand = new RelayCommand<TabItem>(tab =>
        {
            //never reached
        },
        tab =>
        {
            //never reached
        });

        Tabs = new ObservableCollection<TabItem>();

        AddTextseite();
        AddTextseite();          
    }

    void AddTextseite()
    {
        TabItem item = new TextseiteTabItem();
        item.DataContext = new TextSeiteModel();

        Tabs.Add(item);
    }

}

4 个答案:

答案 0 :(得分:1)

您正在尝试使用MVVM,但我看到的奇怪之处是视图模型中的ui元素(Tabs)集合。正确的方法是创建描述Tab项的ViewModel并在那里移动命令。然后它会绑定。要从Tabs中删除选项卡,您应该在Tab视图模型中公开事件,并从PortfolioViewModel附加到它。

当然,我的更改将导致TextseiteTabItem不会显示在TablControl中。但是可以使用TabControl.ItemTemplate和TabControl.ContentTemplate轻松修复它。

答案 1 :(得分:1)

首先,您的CloseTabCommand在您当前的代码段中不执行任何操作://never reached。执行处理程序应该读取类似tab.Visibility = Visibility.CollapsedmyTabControl.Items.Remove(myTabItem)的内容。

其次,正如@Rafal指出的那样,在ViewModel中使用UI元素并不是实现MVVM的正确方法。如果您想要可关闭的选项卡项,正确的方法是派生通用CloseableTabItem控件或在UI层上编写ClosableTabItemBehavior,并使用可设置为ICommand CloseCommand的{​​{1}}绑定到相应的{ ViewModel上的{1}}实例。不可否认,这种方法可能对您的项目来说过于精细。

答案 2 :(得分:0)

here你找到一个带有关闭wpf标签的演示应用程序,也许它适用于你的silverlight版本。

答案 3 :(得分:0)

这是我解决此问题的方法。我承认这不是一个好的解决方案,打破了mvvm模式,但正如@herzmeister所说,其他方法现在对我的项目来说太复杂了。 (但它不是最终的解决方案;-))

TabItemViewModel:

public delegate void CloseTabItemHandler();

public class TextseiteTabItemViewModel : ViewModelBase
{
    public event CloseTabItemHandler CloseTabItem;
    public RelayCommand CloseTabCommand {get; set;}

    public TextseiteTabItemViewModel()
    {
        CloseTabCommand = new RelayCommand(() =>
        {
            if (CloseTabItem == null) return;
            CloseTabItem();
        });
    }
}

TabItemView:

<sdk:TabItem x:Class="PortfolioCreator.TextseiteTabItemView" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
        xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">

    <sdk:TabItem.Header>
        <StackPanel Orientation="Horizontal">
            <Button Content="X" Command="{Binding CloseTabCommand, Mode=TwoWay}" />  
        </StackPanel>
    </sdk:TabItem.Header>

    <sdk:TabItem.Content>
        <Grid x:Name="LayoutRoot">
            ...
        </Grid>
    </sdk:TabItem.Content>
</sdk:TabItem>

父ViewModel:

public class PortfolioViewModel : ViewModelBase
{
    public ObservableCollection<TabItem> Tabs { get; set; }

    public PortfolioViewModel()
    {
        Tabs = new ObservableCollection<TabItem>();

        AddTextseite();
        AddTextseite();
    }

    void AddTextseite()
    {
        var viewmodel = new TextseiteTabItemViewModel();

        TabItem item = new TextseiteTabItemView();
        item.DataContext = viewmodel;

        viewmodel.CloseTabItem += new CloseTabItemHandler(() => 
        { 
            Tabs.Remove(item);
        });

        Tabs.Add(item);
    }
}