【问题标题】:How to close a TabItem in MVVM Light如何在 MVVM Light 中关闭 TabItem
【发布时间】:2012-07-17 12:38:49
【问题描述】:

在我看来,我正在添加动态自定义 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"/>
...

在我的 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);
    }

}

【问题讨论】:

  • 将您的 TabControl.ItemsSource 绑定到模型集合。将模型添加到集合时会出现每个选项卡。删除模型后,每个选项卡都会消失。虚拟机不应该做任何 UI 工作。

标签: silverlight events xaml binding mvvm


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        这是我解决此问题的方法。我承认这不是一个好的解决方案并打破了 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>
        

        父视图模型:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-10
          • 1970-01-01
          • 1970-01-01
          • 2013-11-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多