WPF 简易可拖动的TabControl
代码也不长,就400来行,可添加、删除、拖动Item项,仿照vs2019的样子,
字体、大小、颜色、删除询问、右键询问等均可自定义。
不写xaml,全部后台代码。根据需要自行扩展,如有错误自行修正。
代码
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
public class TabControl : UserControl
{
public class Item
{
public int id;
public Canvas Title_Panel;
public TextBlock title_box;
public Canvas close_box;
public int title_width;
public string title_text;
public Canvas content;
public Item(int i, string t) { id = i; title_text = t; }
}
public static List<Item> items = new List<Item>();
public string Item_Font = "微软雅黑";
public double Item_Size = 12.0;
public double Item_Height = 23.0;
public double Move_Opacity = 0.7;
public Color BackColor = Color.FromArgb(0xff, 0x29, 0x39, 0x56);
public Color Select_PressColor = Color.FromArgb(0xff, 0xf1, 0xc9, 0x83);
public Color Select_PressTextColor = Colors.Black;
public Color CloseButton_PressColor = Color.FromArgb(0xff, 0x26, 0x26, 0x26);
public Color Select_LeaveColor = Color.FromArgb(0xff, 0x3c, 0x53, 0x73);
public Color Select_LeaveTextColor = Colors.White;
public Color Move_Color = Color.FromArgb(0xff, 0x5b, 0x71, 0x99);
public Color CloseButton_LeaveColor = Colors.Gray;
public event EventHandler CloseMouseDown;
public event MouseButtonEventHandler TableMouseRightDown;
public bool Remove_Flag;
public int SelectIndex = 0;
public int MoveIndex = 0;
public bool Visable_Close = true;
public bool Visable_Menu = true;
private Canvas tab_control, Separator_Line;
private bool isDragging = false;
private int Content_Visable = 0;
private ContextMenu ItemMenu = new ContextMenu();
public void Initialize_Control(Canvas obj, double width, double height, double left, double top)
{
tab_control = new Canvas()
{
Width = width,
Height = height,
Clip = new RectangleGeometry(new Rect(0, 0, width, height)),
Background = new SolidColorBrush(BackColor)
};
tab_control.SetValue(Canvas.LeftProperty, left);
tab_control.SetValue(Canvas.TopProperty, top);
Separator_Line = new Canvas()
{
Width = width,
Height = 2,
Background = new SolidColorBrush(Select_PressColor)
};
Separator_Line.SetValue(Canvas.LeftProperty, 0.0);
Separator_Line.SetValue(Canvas.TopProperty, Item_Height);
tab_control.Children.Add(Separator_Line);
if (Visable_Menu)
{
double[] size = ObtainCharSize("◣", Item_Font, Item_Size);
Canvas Menu_Box = new Canvas()
{
Width = size[0] + 10,
Height = Item_Height,
Opacity = 0.8,
Background = new SolidColorBrush(Move_Color),
};
Menu_Box.MouseLeftButtonUp += ItemMenu_MouseLeftButtonUp;
Menu_Box.SetValue(Canvas.LeftProperty, width - Menu_Box.Width);
Menu_Box.SetValue(Canvas.TopProperty, 0.0);
Panel.SetZIndex(Menu_Box, 1000);
tab_control.Children.Add(Menu_Box);
TextBlock Menu_Button = new TextBlock()
{
Width = size[0],
Height = size[1],
Text = "◣",
FontSize = Item_Size,
Foreground = new SolidColorBrush(Select_LeaveTextColor),
Background = Brushes.Transparent,
};
Menu_Button.SetValue(Canvas.LeftProperty, (Menu_Box.Width - size[0]) / 2);
Menu_Button.SetValue(Canvas.TopProperty, (Item_Height - size[1]) / 2);
Menu_Box.Children.Add(Menu_Button);
}
ItemMenu.Opacity = 0.91;
obj.Children.Add(tab_control);
}
private void ItemMenu_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ItemMenu.Items.Clear();
for (int i = 0; i < items.Count; i++)
{
MenuItem menuItem = new MenuItem()
{
Header = items[i].title_text,
Icon = new Image { Source = new BitmapImage(new Uri("pack://application:,,,/images/apply.png")) },
Tag = i
};
menuItem.Click += MenuItem_Click;
ItemMenu.Items.Add(menuItem);
}
ItemMenu.IsOpen = true;
}
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem pL = (MenuItem)sender;
if ((int)pL.Tag != SelectIndex) Set_Index((int)pL.Tag);
}
public void Add_Item(string item_text, FrameworkElement userControl)
{
items.Add(new Item(items.Count, item_text));
int fwidth = 0;
double fheight = 0;
double[] size = new double[2];
for (int i = 0; i < item_text.Length; i++)
{
size = ObtainCharSize(item_text.Substring(i, 1), Item_Font, Item_Size);
fwidth += (int)size[0];
fheight = fheight < size[1] ? size[1] : fheight;
}
double left = 0;
for (int i = 0; i < items.Count; i++) left += items[i].title_width;
items[items.Count - 1].Title_Panel = new Canvas()
{
Width = fwidth + 20,
Height = Item_Height,
Background = Brushes.Transparent,
Tag = items.Count - 1
};
items[items.Count - 1].Title_Panel.SetValue(Canvas.LeftProperty, left);
items[items.Count - 1].Title_Panel.SetValue(Canvas.TopProperty, 0.0);
items[items.Count - 1].title_box = new TextBlock()
{
Text = item_text,
Width = fwidth + 20,
Height = Item_Height,
Padding = new Thickness(10, (Item_Height - fheight) / 2, 0, 0),
Background = new SolidColorBrush(Select_LeaveColor),
FontFamily = new FontFamily(Item_Font),
FontSize = Item_Size,
Foreground = new SolidColorBrush(Select_LeaveTextColor),
};
items[items.Count - 1].Title_Panel.Children.Add(items[items.Count - 1].title_box);
tab_control.Children.Add(items[items.Count - 1].Title_Panel);
Thumb thumb_title = new Thumb()
{
Width = fwidth + 20,
Height = Item_Height,
Opacity = 0,
Tag = items.Count - 1
};
Panel.SetZIndex(thumb_title, 100);
items[items.Count - 1].Title_Panel.Children.Add(thumb_title);
thumb_title.PreviewMouseLeftButtonDown += Title_PreviewMouseLeftButtonDown;
thumb_title.PreviewMouseLeftButtonUp += Title_PreviewMouseLeftButtonUp;
thumb_title.PreviewMouseMove += Thumb_PreviewMouseMove;
thumb_title.MouseLeave += Thumb_title_MouseLeave;
if (TableMouseRightDown != null) thumb_title.AddHandler(PreviewMouseRightButtonDownEvent, new MouseButtonEventHandler(TableMouseRightDown));
thumb_title.DragDelta += Title_DragDelta;
double[] fs = ObtainCharSize("×", Item_Font, Item_Size);
items[items.Count - 1].close_box = new Canvas()
{
Height = Item_Height,
Width = (int)fs[0] + 8,
Background = new SolidColorBrush(Select_LeaveColor),
Tag = items.Count - 1
};
items[items.Count - 1].close_box.PreviewMouseMove += Thumb_PreviewMouseMove;
items[items.Count - 1].close_box.MouseLeave += Thumb_title_MouseLeave;
TextBlock close_flag = new TextBlock()
{
Text = "×",
Height = Item_Height,
Width = (int)fs[0] + 5,
Padding = new Thickness(2, (Item_Height - fheight) / 2, 0, 0),
FontFamily = new FontFamily(Item_Font),
FontSize = Item_Size,
Foreground = new SolidColorBrush(CloseButton_LeaveColor),
Background = Brushes.Transparent,
Cursor = Cursors.Hand,
Tag = items.Count - 1,
};
items[items.Count - 1].close_box.Children.Add(close_flag);
close_flag.PreviewMouseLeftButtonUp += Close_MouseLeftButtonUp;
if (Visable_Close)
{
items[items.Count - 1].close_box.SetValue(Canvas.LeftProperty, left + items[items.Count - 1].title_box.Width);
items[items.Count - 1].close_box.SetValue(Canvas.TopProperty, 0.0);
tab_control.Children.Add(items[items.Count - 1].close_box);
fwidth += (int)fs[0];
items[items.Count - 1].title_width = (int)(items[items.Count - 1].title_box.Width + items[items.Count - 1].close_box.Width + 1);
}
else items[items.Count - 1].title_width = (int)(items[items.Count - 1].title_box.Width + 1);
items[items.Count - 1].content = new Canvas()
{
Width = tab_control.Width,
Height = tab_control.Height - Item_Height - 2,
Clip = new RectangleGeometry(new Rect(0, 0, tab_control.Width, tab_control.Height - Item_Height - 2)),
Background = new SolidColorBrush(Colors.Transparent),
Tag = items.Count - 1,
};
items[items.Count - 1].content.Children.Add(userControl);
items[items.Count - 1].content.SetValue(Canvas.LeftProperty, 0.0);
items[items.Count - 1].content.SetValue(Canvas.TopProperty, Item_Height + 2);
items[items.Count - 1].content.Visibility = SelectIndex == items.Count - 1 ? Visibility.Visible : Visibility.Collapsed;
tab_control.Children.Add(items[items.Count - 1].content);
Set_Select(SelectIndex, true);
}
private void Thumb_title_MouseLeave(object sender, MouseEventArgs e)
{
FrameworkElement pL = (FrameworkElement)sender;
if (!isDragging)
{
if (SelectIndex != (int)pL.Tag)
{
if ((int)pL.Tag >= 0 && (int)pL.Tag < items.Count)
{
items[(int)pL.Tag].title_box.Background = new SolidColorBrush(Select_LeaveColor);
if (Visable_Close) items[(int)pL.Tag].close_box.Background = new SolidColorBrush(Select_LeaveColor);
}
}
}
}
private void Thumb_PreviewMouseMove(object sender, MouseEventArgs e)
{
FrameworkElement pL = (FrameworkElement)sender;
MoveIndex = (int)pL.Tag;
if (!isDragging)
{
if (SelectIndex != (int)pL.Tag)
{
items[(int)pL.Tag].title_box.Background = new SolidColorBrush(Move_Color);
if (Visable_Close) items[(int)pL.Tag].close_box.Background = new SolidColorBrush(Move_Color);
}
}
}
private void Title_DragDelta(object sender, DragDeltaEventArgs e)
{
Thumb pL = (Thumb)sender;
if (items.Count > 1)
{
Content_Visable = SelectIndex + 1 > items.Count - 1 ? SelectIndex - 1 : SelectIndex + 1;
items[Content_Visable].content.Visibility = Visibility.Visible;
Panel.SetZIndex(items[Content_Visable].content, 0);
}
Panel.SetZIndex(pL.Parent as Canvas, 99);
if (Visable_Close) Panel.SetZIndex(items[(int)pL.Tag].close_box, 99);
Panel.SetZIndex(items[(int)pL.Tag].content, 99);
double left = 0;
for (int i = 0; i < items.Count; i++)
{
if (i != SelectIndex)
{
Canvas.SetLeft(items[i].Title_Panel, left);
if (Visable_Close) items[i].close_box.SetValue(Canvas.LeftProperty, left + items[i].title_box.Width);
left += items[i].title_width;
}
}
items[(int)pL.Tag].title_box.Opacity = Move_Opacity;
if (Visable_Close) items[(int)pL.Tag].close_box.Opacity = Move_Opacity;
items[(int)pL.Tag].content.Opacity = Move_Opacity;
isDragging = true;
Canvas.SetLeft(pL.Parent as Canvas, Canvas.GetLeft(pL.Parent as Canvas) + e.HorizontalChange);
if (Visable_Close) Canvas.SetLeft(items[(int)pL.Tag].close_box, Canvas.GetLeft(items[(int)pL.Tag].close_box) + e.HorizontalChange);
Canvas.SetLeft(items[(int)pL.Tag].content, Canvas.GetLeft(pL.Parent as Canvas) + e.HorizontalChange);
}
private void Title_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Thumb pL = (Thumb)sender;
Panel.SetZIndex(pL.Parent as Canvas, 0);
if (Visable_Close) Panel.SetZIndex(items[(int)pL.Tag].close_box, 0);
Panel.SetZIndex(items[(int)pL.Tag].content, 0);
if (isDragging) // move
{
if (items.Count > 1)
{
items[Content_Visable].content.Visibility = Visibility.Collapsed;
}
items[(int)pL.Tag].title_box.Opacity = 1;
if (Visable_Close) items[(int)pL.Tag].close_box.Opacity = 1;
items[(int)pL.Tag].content.Opacity = 1;
Swap_Item();
}
}
private void Title_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Thumb pL = (Thumb)sender;
isDragging = false;
Set_Index((int)pL.Tag);
}
private void Close_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
TextBlock pL = (TextBlock)sender;
Remove_Flag = true;
CloseMouseDown?.Invoke(sender, e);
if (Remove_Flag) Delete_Index((int)pL.Tag);
}
public void Delete_Index(int num)
{
if (items.Count == 1) return;
Set_Select(SelectIndex, false);
int delete = SelectIndex; ;
if (num < SelectIndex) delete = SelectIndex - 1;
else
if (num == SelectIndex)
{
if (num == 0) delete = 0;
else if (num == items.Count - 1)
{
delete = items.Count - 2;
}
}
num = num > items.Count - 1 ? items.Count - 1 : num;
tab_control.Children.Remove(items[num].Title_Panel);
if (Visable_Close) tab_control.Children.Remove(items[num].close_box);
tab_control.Children.Remove(items[num].content);
items.RemoveAt(num);
ArrangeMent();
delete = delete > items.Count - 1 ? items.Count - 1 : delete;
Set_Select(delete, true);
SelectIndex = delete;
}
private void Swap_Item()
{
double swap_point = Canvas.GetLeft(items[SelectIndex].Title_Panel);
double sum_width = items.Sum(w => w.title_width) - items[SelectIndex].title_width;
int place = 0;
if (swap_point < 0) place = 0;
else
if (swap_point > sum_width) place = items.Count - 1;
else
{
for (int i = 0; i < items.Count; i++) //must no Linq
{
if ((swap_point > Canvas.GetLeft(items[i].Title_Panel)) &&
(swap_point < Canvas.GetLeft(items[i].Title_Panel) + items[i].title_width))
{
place = i;
break;
}
}
}
var swap_item = items[SelectIndex];
items.RemoveAt(SelectIndex);
items.Insert(place, swap_item);
ArrangeMent();
Set_Index(place);
}
public void Set_Index(int num)
{
Set_Select(SelectIndex, false);
Set_Select(num, true);
SelectIndex = num;
}
private void Set_Select(int num, bool select)
{
if (select)
{
items[num].title_box.Background = new SolidColorBrush(Select_PressColor);
items[num].title_box.Foreground = new SolidColorBrush(Select_PressTextColor);
if (Visable_Close)
{
items[num].close_box.Background = new SolidColorBrush(Select_PressColor);
(items[num].close_box.Children[0] as TextBlock).Foreground = new SolidColorBrush(CloseButton_PressColor);
}
items[num].content.Visibility = Visibility.Visible;
}
else
{
items[num].title_box.Background = new SolidColorBrush(Select_LeaveColor);
items[num].title_box.Foreground = new SolidColorBrush(Select_LeaveTextColor);
if (Visable_Close)
{
items[num].close_box.Background = new SolidColorBrush(Select_LeaveColor);
(items[num].close_box.Children[0] as TextBlock).Foreground = new SolidColorBrush(CloseButton_LeaveColor);
}
items[num].content.Visibility = Visibility.Collapsed;
}
}
private void ArrangeMent()
{
double left = 0;
for (int i = 0; i < items.Count; i++)
{
items[i].Title_Panel.SetValue(Canvas.LeftProperty, left);
if (Visable_Close)
{
items[i].close_box.SetValue(Canvas.LeftProperty, left + items[i].title_box.Width);
items[i].close_box.Tag = i;
}
items[i].Title_Panel.Tag = i;
(items[i].Title_Panel.Children[1] as Thumb).Tag = i;
items[i].content.SetValue(Canvas.LeftProperty, 0.0);
left += items[i].title_width;
}
}
private double[] ObtainCharSize(string content, string ftype, double fsize)
{
double[] size = new double[2];
content = content == " " ? "`" : content;
FormattedText formattext = new FormattedText(content, CultureInfo.InvariantCulture, FlowDirection.LeftToRight, new Typeface(ftype), fsize, Brushes.Black);
size[0] = formattext.Width;
size[1] = formattext.Height;
return size;
}
}
使用
随意定义一些UserControl,这里举例定义设置不同颜色文字的UserControl
public partial class MainWindow : Window
{
TabControl tabControl;
U1 uc = new U1("000",Colors.OliveDrab);
U1 uc1 = new U1("111", Colors.DimGray);
U1 uc2 = new U1("222", Colors.Salmon);
U1 uc3 = new U1("333", Colors.SteelBlue);
U1 uc4 = new U1("444", Colors.AliceBlue);
U1 uc5 = new U1("555", Colors.Green);
U1 uc6 = new U1("666", Colors.LightPink);
public MainWindow()
{
InitializeComponent();
tabControl = new TabControl();
//tabControl.BackColor = new SolidColorBrush(Colors.SteelBlue); // 背景色
//tabControl.TableMouseRightDown += TabControl_TableMouseRightDown; // item上点击右键事件
//tabControl.Visable_Menu = false; // 显示右侧项目菜单
tabControl.Initialize_Control(MainCanvan, 600.0, 400.0,10,10); // grid里面的Canvas为容器
tabControl.Add_Item("0编辑 Alt-E ", uc);
tabControl.Add_Item("1456编辑 Alt-E ", uc1);
tabControl.Add_Item("2EABC ", uc2);
tabControl.Add_Item("3EABC ", uc3);
tabControl.Add_Item("4ABC ", uc4);
}
}