簡體   English   中英

TabControl在運行時重命名

[英]TabControl renaming in run-time

我正在嘗試創建簡單的界面,用戶可以在TabControl中重命名選項卡。 問題是因為我可以通過GetTabRect方法獲取制表符的位置,所以我無法將TextBox設置為制表符的位置。 這是期望的效果(來自foobar):

在此輸入圖像描述

這是我的效果:

在此輸入圖像描述

下面我插入我的代碼,我嘗試產生這種效果:

      private void renameToolStripMenuItem_Click(object sender, EventArgs e)
    {
        if (selectedTab >= 0 && selectedTab < MainTabs.TabCount)
        {
            Debug.WriteLine("Rename " + MainTabs.Controls[selectedTab].Text);
            Debug.WriteLine(sender.ToString());

            //var CurrentTab = MainTabs.TabPages[selectedTab];
            //TabControl tabControl = MainTabs.Con

            Rectangle rect = MainTabs.GetTabRect(selectedTab);
            Point point = MainTabs.Location;

            Debug.WriteLine(point.ToString() + " " + rect.ToString());

            RenameBox = new TextBox();

            MainTabs.GetControl(selectedTab).Controls.Add(RenameBox);

            //MainTabs

            RenameBox.Show();

            RenameBox.SetBounds(rect.X, rect.Y, rect.Width, rect.Height);


            //MainTab.Controls.Add(RenameBox);
            //this.Controls.Add(RenameBox);
            //components.Add(RenameBox);

            //RenameBox.Location = point;

            //MainTabs.SelectedTab.Controls.Add(RenameBox);

            //MainTabs.GetControl(0).Controls.Add(RenameBox);

            //MainTabs.SelectedTab.

            RenameBox.KeyPress += textBox1_KeyPress;
            //RenameBox.Show();
            //RenameBox.Location = new Point(0, 0);
            //RenameBox.Focus();
            //RenameBox.SetBounds(.GetTabRect(selectedTab));

        }
    }

我應該如何更改代碼以便能夠在運行時重命名Tab名稱?

GetTabRect()返回相對於選項卡控件的位置。 但是您要將文本框添加到標簽頁,它位於標簽頁下方 這就是為什么你的截圖看起來像這樣。 你不能給文本框一個負面的位置,它會被剪裁。 理想情況下,您可以將其添加到選項卡控件,但TabControl顯式禁止此操作。 您可以做的唯一其他事情是將其添加到表單中。

您必須計算正確的位置,將tabrect映射到表格坐標。 並確保它與tabcontrol重疊。 刪除它肯定最好用它的Leave事件完成。 像這樣:

private TextBox AddTextBoxToTab(TabControl tabctl, int index = -1) {
    if (index < 0) index = tabctl.SelectedIndex;
    var rc = tabctl.GetTabRect(index);
    rc = tabctl.RectangleToScreen(rc);
    rc = tabctl.Parent.RectangleToClient(rc);
    var box = new TextBox();
    box.Font = tabctl.Font;
    box.Leave += delegate { box.Dispose(); };
    box.SetBounds(rc.Left, rc.Top, rc.Width, rc.Height);
    tabctl.Parent.Controls.Add(box);
    box.BringToFront();
    box.Focus();
    return box;
}

就個人而言,我會將其實現為一個輕量級的表單,位於選項卡的頂部。

在此輸入圖像描述

要制作輕量級表單,請設置以下屬性:

FormBorderStyle = FormBorderStyle.FixedSingle;
Text            = string.Empty;
StartPosition   = FormStartPosition.Manual;
ControlBox      = false;
ShowInTaskbar   = false;

輕量級表單可以具有更大的TextBox並且可以使用ErrorProvider顯示驗證錯誤。

糟糕!

我直到現在才意識到這個問題是針對WinForms的(編輯歷史記錄顯示標簽后來被添加)。 我將留下答案,以防它對任何想知道如何使用WPF執行此操作的人有用。


您可以使用MVVM模式輕松完成此操作,而無需擔心定位代碼。 完整來源可在此鏈接中找到

在此輸入圖像描述

這使用DocumentVm列表,其中包含NameIsRenaming屬性。 TabControl將其ItemsSource綁定到DocumentVm列表,以便每個Document有一個選項卡。 TabItem的標題包含TextBlockTextBoxButton 單擊該按鈕時,將切換IsRenaming標志。 TextBoxTextBlock的可見性由IsRenaming控制(使用普通和反向轉換器)。 因此,單擊該按鈕可以編輯選項卡的標題。

MainWindow.Xaml:

<Window
    x:Class="RenamableTabs.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:RenamableTabs"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="525"
    Height="350"
    d:DataContext="{d:DesignInstance local:MainWindowVm}"
    mc:Ignorable="d">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
        <local:InvertedBooleanToVisibilityConverter x:Key="InvertedBooleanToVisibilityConverter" />
    </Window.Resources>
    <Grid Margin="8">
        <TabControl ItemsSource="{Binding Path=Documents}">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Path=Name}" Visibility="{Binding Path=IsRenaming, Converter={StaticResource InvertedBooleanToVisibilityConverter}}" />
                        <TextBox Text="{Binding Path=Name}" Visibility="{Binding Path=IsRenaming, Converter={StaticResource BooleanToVisibilityConverter}}" />
                        <Button Command="{Binding Path=RenameCommand}" Content="R" />
                    </StackPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
        </TabControl>
    </Grid>
</Window>

MainWindowVm.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AgentOctal.WpfLib;
using AgentOctal.WpfLib.Services;
using AgentOctal.WpfLib.Services.Message;

namespace RenamableTabs
{
    class MainWindowVm : ViewModel
    {
        public MainWindowVm()
        {
            _messageService = ServiceManager.GetService<AgentOctal.WpfLib.Services.Message.IMessageService>();
            _messageService.Subscribe<DocumentVm.DocumentRenaming>(message =>
            {
                var m = message as DocumentVm.DocumentRenaming;
                foreach (var documentVm in Documents)
                {
                    documentVm.IsRenaming = documentVm == m.Document;
                }
            });

            Documents = new ObservableCollection<DocumentVm>();

            Documents.Add(new DocumentVm() { Name = "Document 1" });
            Documents.Add(new DocumentVm() { Name = "Document 2" });
            Documents.Add(new DocumentVm() { Name = "Document 3" });
        }

        private IMessageService _messageService;

        public ObservableCollection<DocumentVm> Documents { get; }

        private string _name;

        public string Name
        {
            get {return _name;}
            set {SetValue(ref _name, value);}
        }

    }
}

DocumentVm.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Xaml;
using AgentOctal.WpfLib;
using AgentOctal.WpfLib.Commands;
using AgentOctal.WpfLib.Services;
using AgentOctal.WpfLib.Services.Message;

namespace RenamableTabs
{
    class DocumentVm : ViewModel
    {
        public DocumentVm()
        {
            _messageService = ServiceManager.GetService<AgentOctal.WpfLib.Services.Message.IMessageService>();
        }

        private IMessageService _messageService;

        private string _name;
        public string Name
        {
            get { return _name; }
            set { SetValue(ref _name, value); }
        }

        private ICommand _renameCommand;
        public ICommand RenameCommand
        {
            get
            {
                return _renameCommand ?? (_renameCommand = new SimpleCommand((obj) =>
                {
                    _messageService.SendMessage(new DocumentRenaming() { Document = this });
                }));
            }
        }

        private bool _isRenaming = false;
        public bool IsRenaming
        {
            get { return _isRenaming; }
            set { SetValue(ref _isRenaming, value); }
        }

        public class DocumentRenaming : IMessage
        {
            public DocumentVm Document { get; set; }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM