I'm trying to create simple interface where user can rename tab in TabControl. Problem is that since I can get position of tab by GetTabRect method, I can't set TextBox into a place of tab. Here is the desired effect (from foobar):
And here is my effect:
Below I insert my code where I try to make this effect:
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));
}
}
How should I change the code to be able to rename Tab name in runtime?
GetTabRect() returns the position relative to the tab control. But you are adding the textbox to the tabpage, it is located below the tabstrip. Which is why your screenshot looks like that. You cannot give the textbox a negative position, it would be clipped. Ideally you would add it to the tab control, but TabControl explicitly forbids this. The only other thing you can do is add it the form.
You'll have to calculate the correct position, mapping the tabrect to form coordinates. And ensure it overlaps the tabcontrol. Removing it again is surely best done with its Leave event. Like this:
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;
}
Personally, I would implement this as a lightweight form, positioned over the top of the tab.
To make a lightweight form, set the following properties:
FormBorderStyle = FormBorderStyle.FixedSingle;
Text = string.Empty;
StartPosition = FormStartPosition.Manual;
ControlBox = false;
ShowInTaskbar = false;
A lightweight form can have a larger TextBox
and could display validation errors with an ErrorProvider
.
I didn't realize this question was for WinForms until just now (Edit history shows the tag was added later). I'm going to leave the answer in place though, in case it is useful for anyone wanting to know how to do this with WPF.
You can do this rather easily using the MVVM pattern without having to worry about positioning code at all. Full Source is available at this link .
This uses a list of DocumentVm
with a Name
, and an IsRenaming
property. The TabControl
has its ItemsSource
bound to the list of DocumentVm
so that it has one tab per Document. The header of the TabItem
contains a TextBlock
, a TextBox
, and Button
. When you click the button, the IsRenaming
flag is toggled. The TextBox
and TextBlock
have their visibility controlled by IsRenaming
(using a normal, and inverted converter). So clicking the button lets you edit the tab's title.
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; }
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.