4

我真正想要实现的是通过使用组合框作为导航控件来完全控制活动的 TabItem。

这是我到目前为止得到的:

    <TabControl Canvas.Left="26" Canvas.Top="27" Height="100" Name="TabControl1" Width="220">
        <TabItem Header="TabItem1" x:Name="TabItem1">
            <Grid />
        </TabItem>
        <TabItem Header="TabItem2" x:Name="TabItem2">
            <Grid />
        </TabItem>
    </TabControl>


    <ComboBox Canvas.Left="126" Canvas.Top="134" Height="23" Name="CmbTabs" Width="120" 
              ItemsSource="{Binding ElementName=TabControl1, Path=Items}" 
              SelectedValue="{Binding ElementName=TabControl1, Path=SelectedIndex}" 
              SelectedValuePath="TabIndex"
              DisplayMemberPath="Header"/>

仍然唯一实际起作用的是当我按下组合框的切换按钮时显示的列表。即使通过列表选择一个 tabitem 名称也不会做任何事情,它甚至不会更新组合框的选定值文本框。

有什么帮助吗?

编辑:好的,史蒂夫罗宾斯的答案对于“控制”问题很有效。

在组合框下拉列表中选择一个项目不会更新组合框的值这一事实又如何呢?(组合框文本框仍然是空白的!!)

4

4 回答 4

3

如果您试图从 Combo 控制 TabControl,那么它看起来有点倒退。如果您更改选项卡控件上的 SelectedIndex 以将其绑定到组合,它应该可以工作:

<TabControl Canvas.Left="26" Canvas.Top="27" Height="100" Name="TabControl1" Width="220" SelectedIndex="{Binding ElementName=CmbTabs, Path=SelectedIndex}">
        <TabItem Header="TabItem1" x:Name="TabItem1">
            <Grid />
        </TabItem>
        <TabItem Header="TabItem2" x:Name="TabItem2">
            <Grid />
        </TabItem>
    </TabControl>
于 2009-02-13T14:40:07.483 回答
1

我开始研究这个是因为我在组合框上遇到了一些问题。不幸的是,我还没有解决我的问题,但我可以提供一些额外的见解和解决这个问题的方法。首先,让我们从我对原始 xaml 的更改开始。

    <TabControl Height="100" Name="TabControl1" Width="220">
        <TabItem Header="TabItem1" x:Name="TabItem1">
            <TextBlock Text="TabItem1 Content" />
        </TabItem>
        <TabItem Header="TabItem2" x:Name="TabItem2">
            <TextBlock Text="TabItem2 Content" />
        </TabItem>
    </TabControl>


    <ComboBox Height="23" Name="CmbTabs" Width="120" 
        ItemsSource="{Binding ElementName=TabControl1, Path=Items}"
        SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}"
        DisplayMemberPath="Name"
        >
    </ComboBox>

请注意,我们可以在选项卡的 SelectedIndex 和组合控件之间创建一个双向绑定(本例中的默认值),而不是创建从选项卡控件到 ComboBox 的绑定,反之亦然。接下来,让我们向 TabItems 添加一些内容。在这一点上,类似于史蒂夫的建议,我们已经解决了“控制”问题。也就是说,更改选定的 TabItem 会更改选定的 ComboBox 项(您必须相信我,否则请继续阅读!)并且更改 ComboBox 会更改选定的 TabItem。伟大的!

上述 xaml 还将 DiplayMemberPath 属性更改为“名称”。我想你会发现这消除了hughdbrown的“奇怪结果”。回想一下,Header 属性(一个对象)是由 ContentPresenter 包装的。我相信如果没有提供模板,默认行为是将 Header 对象显示为 TextBlock 中的字符串。因此,“奇怪的结果”正确报告 TextBlock 控件不包含 Header 属性。

现在让我们对之前的 ComboBox xaml 进行一些更改。

    <ComboBox Height="23" Name="CmbTabs" Width="120" 
        ItemsSource="{Binding ElementName=TabControl1, Path=Items}"
        SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}"
        >
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}"/>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

这实际上产生了一个有趣的结果,并利用了我们添加到每个 TabItem 的内容。当此代码运行时,您会注意到 ComboBox 现在显示所选 TabItem 的内容。此外,该列表现在为每个 TabItem 显示“System.Windows.Controls.TabItem...”。我们可以将 TextBlock 绑定更改为 {Binding Header} 并显示 Header 对象,但 ComboBox 仍然显示所选 TabItem 的内容。由于星期五晚上很晚,世界上没有足够的啤酒,我没有调查可能的原因。但是,我确实有一个解决方法!

首先,让我们创建一个 ValueConverter 来将 TabControl 的 Items 集合转换为我们可以使用的东西。这是代码。

public class TabItemCollectionConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ItemCollection collection = value as ItemCollection;
        IList<string> names = new List<string>();
        foreach (TabItem ti in collection.SourceCollection)
        {
            names.Add(ti.Header.ToString());
        }
        return names;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }

    #endregion
}

转换器只是从 TabControl 的 Items 集合中创建一个新集合,该集合包含来自每个 TabItem 的字符串化 Header 对象。这适用于简单的 Header 对象,但显然有局限性。现在让我们考虑如何在 xaml 中使用它。

    <ComboBox Height="23" Name="CmbTabs" Width="120" 
        ItemsSource="{Binding ElementName=TabControl1, Path=Items, Converter={StaticResource ItemConverter}}"
        SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}"
        >
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}"/>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

请记住,在 ItemsSource 绑定中使用的 ValueConverter 返回一个新集合。在本例中,我们将 TabControl 的 Items 集合转换为字符串集合。不要忘记创建转换器 StaticResource!它看起来像这样。

    <local:TabItemCollectionConverter x:Key="ItemConverter"/>

现在,使用转换器,整个蜡球按预期工作。

仍然让我感到困惑的是,为什么 ComboBox 会在列表中显示 TabItem 标题,而将 TabItem 内容显示为选择。毫无疑问,有一些明显的解释,但正如我所说,现在是星期五......

希望这可以帮助!

于 2009-09-19T01:40:33.407 回答
0

我一直在玩这个。在进行选择之后,ComboBox 的数据绑定的来源发生了一些变化。或者其他的东西。

我添加了诊断命名空间:

xmlns:debug="clr-namespace:System.Diagnostics;assembly=WindowsBase"

我将您的 <Grid /> 更改为带有大喇叭数字的文本框,以便我可以看到事情确实在发生变化:

    <TabItem Header="TabItem1" x:Name="TabItem1">
        <TextBlock Name="tb1" FontSize="24" Text="1" Width="100" Height="26" />
    </TabItem>

当我运行应用程序时,我发现诊断报告了一个奇怪的结果:

System.Windows.Data 错误:39:BindingExpression 路径错误:在“对象”“TextBlock”(名称=“tb1”)上找不到“标头”属性。绑定表达式:路径=标题;DataItem='TextBlock' (名称='tb2'); 目标元素是'TextBlock'(名称='');目标属性是“文本”(类型“字符串”)

我尝试在启动时在代码中设置一次数据绑定:

    public Window1()
    {
        InitializeComponent();

        Binding positionBinding = new Binding("Items");
        positionBinding.ElementName = "TabControl1";
        positionBinding.Path = new PropertyPath("Items");
        positionBinding.Mode = BindingMode.OneTime;

        CmbTabs.SetBinding(ComboBox.ItemsSourceProperty, positionBinding);
        CmbTabs.DisplayMemberPath = "Header";
    }

并且在选择和更改 TabItem 后,它仍然会切换 CombobBox 以显示未选择的项目。就好像在 TabControl 更改选择后 DataContext 切换到了 TabControl.TabItem.TextBlock 一样。

所以我没有确切的答案给你,但我有一些结果让你努力。

Bea Stollnitz 有一篇关于使用这种诊断技术的好文章。“如何调试 WPF 绑定?”

于 2009-02-16T03:32:17.737 回答
0

基于 Hughdbrown 的回答,我在 MSDN 上找到了这篇文章,将您的问题描述为一个错误。您可以使用此 XAML 重现它(与您的 XAML 存在相反的问题):

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TabControl Name="TabControl1" Width="220" Height="100" Canvas.Left="26" Canvas.Top="27">
        <TabItem x:Name="TabItem1" Header="TabItem1">
            foobar
        </TabItem>
        <TabItem x:Name="TabItem2" Header="TabItem2">
            fizzbuzz
        </TabItem>
    </TabControl>
    <ComboBox Name="CmbTabs" Width="120" Height="23" Canvas.Left="126" Canvas.Top="134"
              ItemsSource="{Binding ElementName=TabControl1, Path=Items}"
              DisplayMemberPath="Length"
              SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}"/>
</Canvas>

正如您所看到的,长度绑定工作正常,除了在下拉列表中,它离开 TabItem 而不是里面的字符串。

我不确定它是否适合您的目的,但您可以通过稍微不那么优雅并在 ComboBoxItems 中复制标题来解决它:

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TabControl Name="TabControl1" Width="220" Height="100" Canvas.Left="26" Canvas.Top="27">
        <TabItem x:Name="TabItem1" Header="TabItem1">
            <Grid/>
        </TabItem>
        <TabItem x:Name="TabItem2" Header="TabItem2">
            <Grid/>
        </TabItem>
    </TabControl>
    <ComboBox Name="CmbTabs" Width="120" Height="23" Canvas.Left="126" Canvas.Top="134"
              SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}">
        <ComboBoxItem>TabItem1</ComboBoxItem>
        <ComboBoxItem>TabItem2</ComboBoxItem>
    </ComboBox>
</Canvas>
于 2009-02-16T22:46:51.927 回答