【问题标题】:WPF: Which solution? TabControl with close button and new tab buttonWPF:哪种解决方案?带有关闭按钮和新标签按钮的 TabControl
【发布时间】:2014-09-07 13:19:18
【问题描述】:

我正在尝试为 TabControl 找到最佳解决方案,它既支持每个 TabItem 上的关闭按钮,又始终将“新标签按钮”显示为最后一个标签。

我找到了一些半有效的解决方案,但我认为那是针对 MVVM 的,我没有使用。足以尝试理解 WPF =)

这是迄今为止我找到的最佳解决方案: http://www.codeproject.com/Articles/493538/Add-Remove-Tabs-Dynamically-in-WPF

我真正理解的解决方案。但问题是它正在使用 ItemsSource,我不希望这样。我想将 ItemsSource 绑定到我自己的集合,而不必在该集合中使用特殊的东西来处理新的选项卡按钮。

我已经搜索了好几天,但找不到一个好的解决方案。 而且我对 WPF 真的很陌生,否则我可能已经适应了我发现的半成品解决方案,或者使它们完整。但不幸的是,目前这超出了我的范围。

任何帮助表示赞赏。

【问题讨论】:

    标签: c# wpf tabcontrol


    【解决方案1】:

    我有一个支持 MVVM 并允许额外内容的开源库,例如将按钮添加到选项卡条中。它是运动型 Chrome 风格的标签,可以撕下。

    http://dragablz.net

    【讨论】:

    • 由于某些原因,我无法看到选项卡上的关闭按钮
    【解决方案2】:

    这是一种不费吹灰之力就可以在最后一个 TabItem 旁边实现添加 (+) 按钮的有点脏的方法。您已经知道如何在 TabItem 标题旁边放置一个删除按钮,所以我没有在此处包含该逻辑。

    基本上这个解决方案的逻辑是

    1. 将 ItemsSource 属性绑定到您自己的集合以及 使用 CompositeCollection 添加 TabItem。
    2. 禁用选择 Add(+) TabItem 而是执行一个动作来加载一个新的选项卡,当它 被点击/选择。

    XAML 位

        <TextBlock x:Name="HiddenItemWithDataContext" Visibility="Collapsed" />
        <TabControl x:Name="Tab1" SelectionChanged="Tab1_SelectionChanged" >
            <TabControl.ItemsSource>
                <CompositeCollection>
                    <CollectionContainer Collection="{Binding DataContext.MyList, Source={x:Reference HiddenItemWithDataContext}}" />
                    <TabItem Height="0" Width="0"  />
                    <TabItem  Header="+" x:Name="AddTabButton"/>
                </CompositeCollection>
            </TabControl.ItemsSource>
        </TabControl>
    

    背后的代码

        private void Tab1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.AddedItems.Contains(AddTabButton))
            {
                //Logic for adding a new item to the bound collection goes here.
                string newItem = "Item " + (MyList.Count + 1);
                MyList.Add(newItem);
                e.Handled = true;
                Dispatcher.BeginInvoke(new Action(() => Tab1.SelectedItem = newItem));
    
            }
        }
    

    【讨论】:

    • 我对肮脏的解决方案没有意见 =) 这仅适用于我自己的项目。但我认为我需要更多解释,因为我无法让它工作。在 XAML 代码中,我得到“对象引用未设置为对象的实例”。在 Collection=... 我的收藏是 ObservableCollection,这应该不是问题?
    • 另一个问题似乎是,由于“+”选项卡在添加时被选中,因此再次按下时不会发生 SelectionChanged。或者那可能是因为我在 XAML 中有错误?
    • Vistual Studio 可能没有对 Reference 标记扩展的适当支持。运行项目时不会出错吗?
    • 它不应该被选中,因为我们使用 e.Handled 取消了选择操作。您的 Tab1_SelectionChanged 代码是什么样的?
    • 不,我在运行项目时没有收到错误消息。我得到一个带有标签栏的窗口,该窗口有一个标签,即“+”标签。这是我的 Tab1_SelectionChanged 代码:if (e.AddedItems.Contains(AddTabButton)) { //向绑定集合添加新项目的逻辑在这里。字符串 newItem = "项目" + (colFilters.Count + 1);过滤器 newFilter = new Filter() { Name = newItem }; colFilters.Add(newFilter); e.Handled = true; Dispatcher.BeginInvoke(new Action(() => Tab1.SelectedItem = newItem));我只使用该功能一次,当添加“+”-tab 时,再也不会。
    【解决方案3】:

    您可以制作一个附加“添加”选项卡的转换器。这样,您的视图模型中的选项卡集合将仅包含真正的选项卡。

    问题是如何知道何时选择了“添加”选项卡。您可以制作一个 TabItem 行为,该行为在选择选项卡时执行命令。顺便说一句,我最近在另一个问题上推荐了这个,所以你可以从那里获取代码:TabItem selected behavior

    【讨论】:

      【解决方案4】:

      虽然我实际上没有编码的解决方案,但我可以就 WPF/MVVM 模式中最有可能处理此问题的适当方法提供一些见解。

      首先,如果我们将请求分解如下:

      1. 您有一系列要显示的元素。
      2. 您希望用户能够从序列中删除单个元素。
      3. 您希望用户能够向序列中添加新元素。

      此外,由于您尝试使用TabControl,您还希望获得Selector 控件提供的行为(元素选择),以及显示元素(内容)的区域,即已选中。

      所以,如果我们坚持这些行为,你会没事的,因为用户界面控件可以在外观和感觉方面进行自定义。


      当然,最好的控件是TabControl,您已经尝试使用它。如果我们使用这个控件,它就满足第一项。

      <TabControl ItemsSource="{Binding Path=Customers}" />
      

      之后,您可以自定义每个元素,在您的情况下,您想为每个元素添加一个Button,这将执行一个命令以从序列中删除该元素。这将满足第二项。

      <TabControl ...>
        <TabControl.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Path=CustomerId}" />
              <Button Command="{Binding Path=RemoveItemCommand, Mode=OneTime,
                                RelativeSource={RelativeSource FindAncestor,
                                                AncestorType={x:Type TabControl}}"
                      CommandParameter="{Binding}" />
            </StackPanel>
          </DataTemplate>
        <TabControl.ItemTemplate>
      </TabControl>
      

      最后一部分有点困难,实际上需要你创建一个继承自TabControl 类的自定义控件,添加一个ICommand DependencyProperty,并自定义控件模板以便它不仅显示TabPanel,而且在它旁边还显示一个Button,它处理您刚刚创建的DependencyProperty(按钮的外观和感觉也必须自定义)。完成所有这些操作后,您就可以显示自己的 TabControl 版本,它有一个虚假的 TabItem,当然这是您的“添加”按钮。这说起来容易做起来难,祝你好运。请记住,TabPanel 包含多行并且可以水平或垂直移动。基本上,这最后一部分一点都不容易。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-10
        • 2017-08-21
        • 2012-01-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-28
        相关资源
        最近更新 更多