【问题标题】:Binding MenuItem's IsChecked to TabItem's IsSelected with dynamic tabs使用动态选项卡将 MenuItem 的 IsChecked 绑定到 TabItem 的 IsSelected
【发布时间】:2011-11-01 19:26:07
【问题描述】:

我有一个标签项列表,其中动态添加了视图。每次用户添加视图时,都会创建一个新的选项卡项。我现在正在尝试将菜单绑定到 tabcontrol 的项目,以便用户可以从菜单中选择当前是活动视图的视图。

我的菜单是这样绑定的:

<Menu Background="Transparent">
    <MenuItem Style="{StaticResource TabMenuButtonStyle}" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=Items}" ItemContainerStyle="{StaticResource TabMenuItem}"></MenuItem>
</Menu>

这可以正常工作并且具有预期的效果(每个菜单项都是所有打开选项卡的列表)。

我有以下样式将菜单项绑定到选项卡项的 IsSelected 属性:

<Setter Property="IsChecked" Value="{Binding Path=IsSelected, Mode=TwoWay}" />

我的问题是,这个绑定不起作用。绑定错误消息表明它在视图对象上找不到 IsSelected 属性。我不希望它使用特定视图,而是希望它查看视图当前绑定到的选项卡项。

我尝试了以下方法,但仍然出现绑定错误:

<Setter Property="IsChecked" Value="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource AncestorType=TabItem}}}" />

这表明它无法为每个菜单项找到 TabItem 类型的祖先(这是有道理的,因为菜单项的祖先不是它所绑定的。)

有什么方法可以访问作为绑定传入的项目的父项,以便绑定到它的属性?

更新:

根据 Yadyn 的建议,我决定创建一个值转换器并返回选项卡项。

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        ItemCollection ic = (ItemCollection)value;
        List<TabItem> tabItems = new List<TabItem>();
        foreach (var obj in ic) {
            tabItems.Add((TabItem)obj);
        }
        return tabItems;
    }

这使得 IsSelected 绑定到 IsChecked 对静态项(已创建其选项卡项的 TabControl)有效,但对于动态添加的视图,永远不会调用 Convert 方法。就像 TabControl 没有向其项目的活页夹发送已更改的更新。下面是 MenuItem 现在的连接方式:

<MenuItem Style="{StaticResource TabMenuButtonStyle}" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabControl}}, Path=Items, Mode=OneWay, NotifyOnSourceUpdated=True,  Converter={StaticResource TabControlItemConverter}}" ItemContainerStyle="{StaticResource TabMenuItem}"></MenuItem>

【问题讨论】:

  • 菜单是 TabControl 的子项还是同级项?我认为唯一允许的 tabcontrol 子项是 TabItems
  • 更像兄弟姐妹。我在 ControlTemplate 中为 TabControl 定义了菜单,因此它可以调用 TabControl 的项目集合。

标签: wpf xaml mvvm


【解决方案1】:

TabControl.Items 将使您返回视图,因为这是您绑定到 TabControl 以拥有动态选项卡视图的内容。

不幸的是,没有可以直接绑定到 TabControl 上的属性来获取 TabItems 的集合。这些实际上是 Items 绑定集合中每个项目的 ItemContainers。

你可能会做的是创建一个转换器或其他东西。您可以尝试使用 myTabControl.ItemContainerGenerator.ContainerFromItem 并传入视图对象以取回包装它的实际 TabItem。然后您的 IsSelected 绑定将起作用。

您可以考虑直接绑定到 TabControl 本身而不是 Items 属性。然后转换器可以轻松地对 ContainerFromItem 进行上述调用。然后,您必须自己枚举 Items 属性(为每个属性调用 ContainerFromItem),从转换器返回 List&lt;TabItems&gt;

无论如何,希望这能让你走上正轨!

【讨论】:

  • 让我开始走上正轨,但并没有完全解决动态视图的问题。不过,让我继续前进。
【解决方案2】:

这里有一些更简单的东西。定义一个顶级视图模型,其中包含代表选项卡和菜单项的视图模型集合,如下所示

//Not showing here the details of implementing INPC
public class MyCustomCompositeViewModel:INotifyPropertyChanged
{
  public ObservableCollection<CompositeViewItem>CompositeItems{get;set;}
  public CompositeViewItem SelectedItem{get;set;}
}

在视图上,将 tabitems 绑定到 CompositeItems 集合,并将选定的选项卡项绑定到 selectedItem。您可以类似地绑定 MenuItems

compositeviewitem 应该提供像项目名称这样的属性(用于显示在选项卡和菜单上),也许还有视图需要渲染的额外数据。希望这是有道理的。

【讨论】:

    猜你喜欢
    • 2010-09-20
    • 2012-03-08
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-23
    • 1970-01-01
    相关资源
    最近更新 更多