wpf 从TabControl中删除选项卡:错误4找不到绑定源

xv8emn3q  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(198)

我有一个TabControl,它有一个特殊的“+ tab”,定义如下:

<TabControl x:Name="ProjectsTabControl">
   <local:ProjectTabItem x:Name="AddProjectTabTabItem" Header="+" MouseUp="AddProjectButton_Click" PreviewMouseDown="AddProjectTabTabItem_PreviewMouseDown"/>
</TabControl>

“MouseDown”只是将鼠标事件参数标记为已处理(为了防止+选项卡被选中)。“Button_Click”添加具有以下样式的新选项卡:

<Window.Resources>
    <Style x:Key="CloseableTabItemStyle" TargetType="local:ProjectTabItem">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <DockPanel>
                        <TextBlock Text="{Binding}" Margin="0,0,5,0"/>
                        <Button Content="X" Click="CloseButton_Click" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:ProjectTabItem}}}"/>
                    </DockPanel>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

这些是我使用的“实际”选项卡。每个这样的标签在其标题中都有一个“关闭按钮”。正如您所看到的,关闭按钮的标记被设置为ProjectTabItem祖先。
我的CloseButton逻辑如下:

private async void CloseButton_Click(object sender, RoutedEventArgs e)
{
    if (sender is Button closeButton && closeButton.Tag is ProjectTabItem tabItem)
    {
        ProjectsTabControl.Items.Remove(tabItem);
        if (ProjectsTabControl.SelectedIndex == ProjectsTabControl.Items.Count - 1)
        {
            ProjectsTabControl.SelectedIndex--;
        }
    }
}

这里的想法是防止+选项卡被选中(然而,即使我选择了+选项卡,我很快就会描述的问题也会发生)。
当我关闭最后一个选项卡(即+选项卡之前的最后一个选项卡)时,我看到以下错误

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 'ProjectTabItem' (Name=''); target property is 'NoTarget' (type 'Object')

只有在关闭标签时选择标签时才会发生这种情况。
看起来如果我在关闭“最后一个”标签之前抢先打开一个新标签,这个问题就不会发生。(然而,这对我没有帮助,因为我想允许除了+选项卡之外根本没有选项卡。
这是什么原因造成的?我该怎么修复它?
编辑:我已经找到了一个,我猜,解决办法here。在删除选项卡之前设置tabItem.Template = null;实际上解决了这个问题。所以让我把我的问题改成:为何会出现这种情况呢?这个“解决方案”实际上是一个解决方案,还是它只是抑制了我代码中的一些潜在的重要问题?

plicqrtu

plicqrtu1#

只要你使用代码隐藏,你就永远不会从WPF中得到乐趣。你总是会踩到“变通方案陷阱”。如果你遵循MVVM模式,事情会变得容易得多。
我刚刚在我的应用程序中创建了一个TabControl,它绑定到Observable Collection
在这个Observable Collection中有TabItemModels:

public class TabItemModel : ViewModelBase
{
    private string _header;
    private ObservableObject _content;

    public string Header
    {
        get { return _header; }
        set
        {
            _header = value;
            RaisePropertyChanged(nameof(Header));
        }
    }
    public ObservableObject Content
    {
        get { return _content; }
        set
        {
            _content = value;
            RaisePropertyChanged(nameof(Content));
        }
    }

    private readonly IMessenger _messenger;
    public RelayCommand CloseTabCommand { get; set; }

    public TabItemModel(IMessenger messenger)
    {
        _messenger = messenger;
        CloseTabCommand = new RelayCommand(CloseThisTab);
    }

    private void CloseThisTab()
    {
        _messenger.Send(this);
    }
}

这里的XAML -此TabControl的一部分:

<TabControl Grid.Column="1" Grid.ColumnSpan="2" 
                Grid.Row="1" Grid.RowSpan="2"
                ItemsSource="{Binding TabItems.Models}"
                SelectedItem="{Binding ActiveTab, Mode=TwoWay}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="Black" BorderThickness="2" CornerRadius="5" Margin="10,0,0,0">
                    <Grid Width="auto">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="9*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Header}"
                                      FontSize="12" FontWeight="DemiBold"
                                      HorizontalAlignment="Left"
                                      VerticalAlignment="Center"
                                      Margin="12,0"
                                      Width="auto"/>

                        <Button Grid.Column="1"
                                   Foreground="White" Command="{Binding CloseTabCommand}"
                                   HorizontalAlignment="Right"
                                   Padding="5"
                                   VerticalContentAlignment="Center"
                                   Margin="5">
                            <Button.Content>
                                <Image Source="/icon-delete.png" Height="12" Width="12"/>
                            </Button.Content>

                        </Button>
                    </Grid>
                </Border>
            </DataTemplate>
        </TabControl.ItemTemplate>

MainViewModel中的声明:

[ObservableProperty]
    TabItemViewModel tabItems;

    [ObservableProperty]
    TabItemModel activeTab;

XAML中的按钮触发TabItemModel中的Relay-Command,它向View-Model发送消息以关闭选项卡。我只是从集合中删除了这个特定的模型:

public void Handle(TabItemModel message)
    {
        if (TabItems.Models.Count > 0)
        {
            TabItems.Models.Remove(message);
        }
    }

对我来说很好。

相关问题