1

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

我的自定义 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"/>
...

在我的视图模型中:

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

4 回答 4

1

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

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

于 2012-07-17T13:07:47.303 回答
1

首先,您CloseTabCommand在当前的代码段中什么都不做://never reached. 执行处理程序应该读取类似tab.Visibility = Visibility.Collapsedor的内容myTabControl.Items.Remove(myTabItem)

其次,正如@Rafal 指出的那样,在 ViewModel 中使用 UI 元素并不是实现 MVVM 的正确方法。如果您想要可关闭的选项卡项,正确的方法是派生通用控件或在 UI 层上CloseableTabItem编写一个可绑定到ViewModel 上相应实例的可设置表。诚然,这种方法对于您的项目来说可能过于复杂。ClosableTabItemBehaviorICommand CloseCommandICommand

于 2012-07-17T13:44:25.943 回答
0

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

于 2012-07-17T13:46:47.127 回答
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();
        });
    }
}

选项卡项视图:

<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>

父视图模型:

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);
    }
}
于 2012-07-17T16:33:51.103 回答