使用动态选项卡将MenuItem的IsChecked绑定到TabItem的IsSelected

时间:2011-11-01 19:26:07

标签: wpf xaml mvvm

我有一个标签项列表,其中包含动态添加的视图。每次用户添加视图时,都会创建一个新选项卡项。我现在正在尝试将菜单绑定到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属性。我不希望它使用specfic视图,而是希望它查看视图当前绑定的选项卡项。

我尝试过以下操作,但仍然遇到绑定错误:

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

这使得IsSecked绑定IsSecked适用于静态项(已创建其选项卡项的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>

2 个答案:

答案 0 :(得分:0)

TabControl.Items会让你返回视图,因为这是你绑定到TabControl以获得动态标签视图。

不幸的是,没有可以直接在TabControl上绑定的属性,它将为您提供TabItems的集合。这些实际上是Items绑定集合中每个项目的ItemContainers。

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

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

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

答案 1 :(得分:0)

这是更简单的事情。定义一个顶层视图模型,它包含一组视图模型,表示标签和菜单项,如此

//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应提供项目名称(用于在选项卡和菜单上显示)等属性,以及View可能需要渲染的其他数据。希望这是有道理的。