通过双击名称更改 TabItem 的名称

Change a TabItem's name by double clicking the name

我有一个 TabControl 并且我正在尝试允许用户更改选项卡名称...但只有当名称被双击时。这样,用户可以单击不同的选项卡名称来简单地更改活动选项卡,但也可以根据需要更改选项卡名称。

到目前为止我尝试过的 是捕获 MouseDoubleClickLostFocus 事件,然后设置“可聚焦”属性仅当双击选项卡名称时为真。此方法的问题是 LostFocus 事件在双击后 立即触发 ,大概是因为焦点被设置到 TabItem 的内容。

我的选项卡控件XAML:

    <Mah:MetroAnimatedTabControl x:Name="ViewTabs" DataContext="{Binding MyTabsViewModel}" ItemsSource="{Binding}">
        <Mah:MetroAnimatedTabControl.ItemTemplate>
            <DataTemplate DataType="{x:Type viewModels:MyTabViewModel}">
                <TextBox x:Name="TabNameTextBox" 
                         Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                         MouseDoubleClick="TabNameTextBox_MouseDoubleClick"
                         LostFocus="TabNameTextBox_LostFocus"
                         Cursor ="Arrow"/>        
            </DataTemplate>
        </Mah:MetroAnimatedTabControl.ItemTemplate>
    </Mah:MetroAnimatedTabControl>

事件 MouseDoubleClickLost Focus 背后的代码:

    private void TabNameTextBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var textBox = (TextBox)sender;
        textBox.Focusable = true;
        textBox.Focus();
        textBox.SelectAll();
    }

    private void TabNameTextBox_LostFocus(object sender, RoutedEventArgs e)
    {
        var textBox = (TextBox)sender;
        textBox.Focusable = false;
    }

我发现 similar question 提问者无法触发 Lost Focus 事件。在我的情况下,它在我预期之前就开始了。

我得到了以下与标准 WPF TabControl 一起工作的信息。我的猜测是它也应该适用于 Mah:MetroAnimatedTabControl

MainWindow.xaml:

<TabControl ItemsSource="{Binding Items}">
    <TabControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:Item}">
            <Grid>
                <TextBox x:Name="textBox" Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" LostFocus="textBox_LostFocus" Visibility="Collapsed"/>
                <TextBlock x:Name="textBlock" Text="{Binding Name}" MouseDown="TextBlock_MouseDown"/>
            </Grid>
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <DataTemplate DataType="{x:Type local:Item}">
            <TextBlock Text="{Binding Contents}"/>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    private ObservableCollection<Item> items;

    public MainWindow()
    {
        InitializeComponent();
        Items.Add(new Item() { Name = "Item 1" });
        Items.Add(new Item() { Name = "Item 2" });
        Items.Add(new Item() { Name = "Item 3" });
        this.DataContext = this;
    }

    public ObservableCollection<Item> Items
    {
        get
        {
            if (items == null)
                items = new ObservableCollection<Item>();
            return items;
        }
    }

    private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
    {
        if (e.ClickCount == 2 && e.ButtonState == MouseButtonState.Pressed)
        {
            var grid = (Grid)VisualTreeHelper.GetParent(sender as UIElement);
            (sender as UIElement).Visibility = Visibility.Collapsed;
            grid.Children[0].Visibility = Visibility.Visible;
            grid.Children[0].Focus();
            ((TextBox)grid.Children[0]).SelectAll();
            e.Handled = true;
        }
    }

    private void textBox_LostFocus(object sender, RoutedEventArgs e)
    {
        var grid = (Grid)VisualTreeHelper.GetParent(sender as UIElement);
        (sender as UIElement).Visibility = Visibility.Collapsed;
        grid.Children[1].Visibility = Visibility.Visible;
    }
}

Item.cs:

public class Item : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public Item()
    {
        this.PropertyChanged += OnItemPropertyChanged;
    }

    private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(Name))
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Contents)));
        }
    }

    private string name;

    public string Name { get => name; set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name))); } }

    public string Contents { get => $"Contents of {Name}"; }


}

我 double-clicked“项目 3”header 名称后的屏幕截图: