26

当我添加一个新选项卡然后将其删除时,我的应用程序会抛出此错误消息:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.TabControl', AncestorLevel='1''. BindingExpression:Path=TabStripPlacement; DataItem=null; target element is 'TabItem' (Name=''); target property is 'NoTarget' (type 'Object')

如果我添加一个新标签,切换到另一个标签,切换回来,然后删除它,它不会抱怨。似乎在切换过程中“更新”了一些东西,但我不知道是什么以及如何修复它们。

这是我的 xaml 文件:

<Window x:Class="MyHomework__MVVM_.MyHomeworkView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="My Homework" Height="450" Width="800" ResizeMode="CanMinimize">
    <Grid Margin="0,0,10,10">
        <TabControl HorizontalAlignment="Left" Height="330" VerticalAlignment="Top" Width="764" Margin="10,10,0,0" ItemsSource="{Binding AllTabs}" SelectedItem="{Binding SelectedTab}">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding Header}"/>
                    <Setter Property="ContentTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <Grid>
                                    <TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" FontSize="16" AcceptsReturn="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" TextChanged="OnTextChanged">
                                    </TextBox>
                                </Grid>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="FontSize" Value="20"/>
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>
        <Button Content="Add Course" HorizontalAlignment="Left" VerticalAlignment="Top" Width="105" Margin="10,351,0,0" Height="50" Command="{Binding AddCourseCommand}"/>
        <Button Content="Drop Course" HorizontalAlignment="Left" VerticalAlignment="Top" Width="76" Margin="126,379,0,0" Height="22" Command="{Binding DropCourseCommand, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Content="Save HW" HorizontalAlignment="Left" VerticalAlignment="Top" Width="105" Margin="669,351,0,0" Height="50" Command="{Binding SaveHomeworkCommand, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>

这是我添加/删除标签的代码:

public void AddNewTab()
        {
            NewCourseName ncn = new NewCourseName();
            ncn.Owner = mainWindow;
            ncn.ShowDialog();
            if (ncn.courseName != null)
            {
                MyHomeworkModel newTab = new MyHomeworkModel();
                newTab.Header = ncn.courseName;
                newTab.Text = "";
                AllTabs.Add(newTab);
                SelectedTab = newTab;
            }
        }

public void RemoveTab()
        {
            DropCourseConfirmation dcc = new DropCourseConfirmation();
            dcc.Owner = mainWindow;
            dcc.ShowDialog();
            if (dcc.drop == true)
            {
                int index = AllTabs.IndexOf(SelectedTab);
                AllTabs.Remove(SelectedTab);

                if (AllTabs.Count > 0)
                {
                    if (index == 0)
                    {
                        SelectedTab = AllTabs[0];
                    }
                    else
                    {
                        SelectedTab = AllTabs[--index];
                    }
                }
                else
                {
                    SelectedTab = null;
                }
            }
        }

如果您需要查看更多代码,请告诉我。提前致谢。

4

3 回答 3

18

正如Zarat提到的,Windows 8 中 TabItem 的默认样式具有在删除后触发的触发器,然后查找现在丢失的 TabControl。我认为这是一个错误,因为添加和删除 TabItems 是一个非常常见的场景,不是吗?

我发现作为一种解决方法,可以删除 TabItem 的模板:

foreach (var item in TabControl.Items)
{
    var tabitem = item as TabItem;
    // if this is the item to remove
    tabitem.Template = null;
    TabControl.Items.Remove(item);
}

这在我的场景中看起来不错,因为我不会再使用 TabItem 了。

我还尝试清除模板的触发器集合或清除其触发器的条件集合,但不允许这样做(错误)。
此外,似乎没有办法禁用触发器。

于 2014-01-08T16:41:47.880 回答
7

这不是错误,只是 WPF 绑定引擎在更新绑定并注意到某些内容丢失时发出的一些噪音。很遗憾,它不能被静音。也许它值得在 Connect 或 MSDN 论坛上报告,但不要指望任何快速反应。

您注意到的消息来自 aero2.normalcolor.xaml - Windows 8 的默认样式。如果您在默认位置安装了 VS 2012 SP 2,您可以在此处找到它们:C:\Program Files (x86)\Microsoft Visual Studio 11.0 \混合\系统主题\ Wpf

在这个文件中,有几个 MultiDataTrigger 有条件检查相对源上的 TabStripPlacement,寻找父 TabControl。因此,当您从 TabControl 中删除 TabItem 时,绑定引擎可能会尝试更新绑定并发现父项丢失,并记录警告。这完全没问题,因为 TabItem 已被删除并且您不再关心样式(如果您要再次添加它,绑定将被重新评估并且一切都会好起来的)。

现在我不知道他们为什么在 Windows 8 的 RelativeSource 上检索 TabStripPlacement,因为 TabItem 本身似乎带有其父 TabStripPlacement 的副本。所有其他默认样式都使用 TabStripPlacement 的本地副本进行绑定。因此,如果您喜欢冒险,您可能希望将样式复制到您自己的资源字典中,并在调试期间使用“固定”版本以减少噪音......

于 2013-05-03T21:11:41.407 回答
1

我相信这是最终修复,它将在 XAML 级别(没有代码背后)工作,并且应该适用于每个人。

在您的 TabControl 中,添加此ItemContainerStyle

<TabControl ItemContainerStyle="{StaticResource FixTabStripTabItemStyle}"/>

并将此Style和此ControlTemplate添加到您的窗口/应用程序资源

<!--This should be used whenever a TabControl is using ItemsSource, as some Bindings are failing when the tabs are removed/added-->
<Style x:Key="FixTabStripTabItemStyle" TargetType="{x:Type TabItem}">
    <Setter Property="MinWidth" Value="60" />
    <Setter Property="Template" Value="{DynamicResource FixTabStripTabItemControlTemplate}"/>
</Style>

<ControlTemplate x:Key="FixTabStripTabItemControlTemplate" TargetType="{x:Type TabItem}">
    <Grid x:Name="templateRoot" SnapsToDevicePixels="True">
        <Border x:Name="mainBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Background}" Margin="0">
            <Border x:Name="innerBorder" BorderBrush="#FFACACAC" BorderThickness="1,1,1,0" Background="White" Margin="-1" Opacity="0"/>
        </Border>
        <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" Focusable="False" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ItemsControl}}}"/>
    </Grid>
    <ControlTemplate.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Left"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" TargetName="mainBorder">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFECF4FC" Offset="0"/>
                        <GradientStop Color="#FFDCECFC" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FF7EB4EA"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,0,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,0,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Bottom"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" TargetName="mainBorder">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFECF4FC" Offset="0"/>
                        <GradientStop Color="#FFDCECFC" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FF7EB4EA"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,0,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,0,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Right"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" TargetName="mainBorder">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFECF4FC" Offset="0"/>
                        <GradientStop Color="#FFDCECFC" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FF7EB4EA"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="0,1,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="0,1,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" TargetName="mainBorder">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#FFECF4FC" Offset="0"/>
                        <GradientStop Color="#FFDCECFC" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FF7EB4EA"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,1,0"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,1,0"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Left"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Opacity" TargetName="contentPresenter" Value="0.56"/>
            <Setter Property="Background" TargetName="mainBorder" Value="#FFF0F0F0"/>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FFD9D9D9"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,0,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,0,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Bottom"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Opacity" TargetName="contentPresenter" Value="0.56"/>
            <Setter Property="Background" TargetName="mainBorder" Value="#FFF0F0F0"/>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FFD9D9D9"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,0,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,0,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Right"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Opacity" TargetName="contentPresenter" Value="0.56"/>
            <Setter Property="Background" TargetName="mainBorder" Value="#FFF0F0F0"/>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FFD9D9D9"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="0,1,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="0,1,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Opacity" TargetName="contentPresenter" Value="0.56"/>
            <Setter Property="Background" TargetName="mainBorder" Value="#FFF0F0F0"/>
            <Setter Property="BorderBrush" TargetName="mainBorder" Value="#FFD9D9D9"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,1,0"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,1,0"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Left"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,0,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,0,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Left"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Panel.ZIndex" Value="1"/>
            <Setter Property="Margin" Value="-2,-2,0,-2"/>
            <Setter Property="Opacity" TargetName="innerBorder" Value="1"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,0,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,0,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Bottom"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,0,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,0,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Bottom"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Panel.ZIndex" Value="1"/>
            <Setter Property="Margin" Value="-2,0,-2,-2"/>
            <Setter Property="Opacity" TargetName="innerBorder" Value="1"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,0,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,0,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Right"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="0,1,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="0,1,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Right"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Panel.ZIndex" Value="1"/>
            <Setter Property="Margin" Value="0,-2,-2,-2"/>
            <Setter Property="Opacity" TargetName="innerBorder" Value="1"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="0,1,1,1"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="0,1,1,1"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="false"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,1,0"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,1,0"/>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true"/>
                <Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Panel.ZIndex" Value="1"/>
            <Setter Property="Margin" Value="-2,-2,-2,0"/>
            <Setter Property="Opacity" TargetName="innerBorder" Value="1"/>
            <Setter Property="BorderThickness" TargetName="innerBorder" Value="1,1,1,0"/>
            <Setter Property="BorderThickness" TargetName="mainBorder" Value="1,1,1,0"/>
        </MultiDataTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
于 2021-10-04T13:35:56.447 回答