Cómo crear tabs trapezoidales en el control de tabs WPF

¿Cómo crear tabs trapezoidales en el control de tabs WPF?
Me gustaría crear tabs no rectangulares que se vean como tabs en Google Chrome o como tabs en el editor de código de VS 2008.

¿Se puede hacer con estilos de WPF o se debe dibujar en código?

¿Hay algún ejemplo de código disponible en internet?

Editar:

Hay muchos ejemplos que muestran cómo redondear esquinas o cambiar colores de tabs, pero no pude encontrar ninguno que cambie la geometría de las tabs como estos dos ejemplos:

Fichas del editor de código VS 2008
Fichas del editor de código VS 2008

Pestañas de Google Chrome
texto alternativo

Las tabs de estos dos ejemplos no son rectangularjs, sino trapecios.

Traté de encontrar algunas plantillas de control o soluciones para este problema en Internet, pero no encontré ninguna solución “aceptable” para mí. Así que lo escribí a mi manera y aquí hay un ejemplo de mi primer (y último =) bash de hacerlo:

                                      

 using System; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; namespace TabControlTemplate { public partial class Window1 { public Window1() { InitializeComponent(); } } public class ContentToMarginConverter: IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return new Thickness(0, 0, -((ContentPresenter)value).ActualHeight, 0); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } public class ContentToPathConverter: IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { var ps = new PathSegmentCollection(4); ContentPresenter cp = (ContentPresenter)value; double h = cp.ActualHeight > 10 ? 1.4 * cp.ActualHeight : 10; double w = cp.ActualWidth > 10 ? 1.25 * cp.ActualWidth : 10; ps.Add(new LineSegment(new Point(1, 0.7 * h), true)); ps.Add(new BezierSegment(new Point(1, 0.9 * h), new Point(0.1 * h, h), new Point(0.3 * h, h), true)); ps.Add(new LineSegment(new Point(w, h), true)); ps.Add(new BezierSegment(new Point(w + 0.6 * h, h), new Point(w + h, 0), new Point(w + h * 1.3, 0), true)); return ps; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } #endregion } } 

Estos dos conversores que escribí para ajustar el tamaño de la pestaña a su contenido. En realidad, creo el objeto Path dependiendo del tamaño del contenido. Si no necesita tabs con varios anchos, puede usar alguna copia modificada de esto:

  

pantalla:

captura de pantalla

proyecto de muestra (vs2010)

Nota: Este es solo un apéndice de la gran respuesta de los rooks.

Mientras que la solución de rooks estaba funcionando perfectamente en tiempo de ejecución para mí, tuve algunos problemas al abrir MainWindow en la superficie del diseñador VS2010 WPF: el diseñador lanzó excepciones y no mostró la ventana. Además, todo el ControlTemplate para TabItem en TabControl.xaml tenía una línea azul ondulada y una información sobre herramientas me decía que se había producido una NullReferenceException. Tuve el mismo comportamiento al mover el código relevante a mi aplicación. Los problemas estaban en dos máquinas diferentes, así que creo que no estaba relacionado con ningún problema de mi instalación.

En caso de que alguien experimente los mismos problemas, he encontrado una solución para que el ejemplo funcione ahora en tiempo de ejecución y en el diseñador también:

Primero : Reemplazar en el código TabControl-XAML …

            

… por …

      

Segundo : Reemplace al final del método Convertir de la clase ContentToPathConverter …

 return ps; 

… por …

 PathFigure figure = new PathFigure(new Point(1, 0), ps, false); PathGeometry geometry = new PathGeometry(); geometry.Figures.Add(figure); return geometry; 

No tengo ninguna explicación de por qué esto funciona estable en el diseñador pero no en el código original de rooks.

Acabo de terminar un control de tabs similar a Google Chrome para WPF. Puede encontrar el proyecto en https://github.com/realistschuckle/wpfchrometabs y las publicaciones de blog describiéndolo en

  • Control de tabs WPF estilo Google Chrome
  • ChromeTabControl y Visual Children en WPF
  • WPF Chrome Tabs funcionando

Espero que te ayude a comprender mejor cómo crear un control de tabs personalizado desde cero.

                               

Sé que esto es antiguo, pero me gustaría proponer:

enter image description here

XAML:

                                  

ViewModel:

  using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Shapes; using System.ComponentModel; using System.Globalization; using System.Windows.Media; namespace TrapezoidTab { public class TabHeaderViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private string _tabHeaderText; private List _polygonPoints; private PointCollection _pointCollection; public TabHeaderViewModel(string tabHeaderText) { _tabHeaderText = tabHeaderText; TabPolygonPoints = GenPolygon(); } public PointCollection TabPolygonPoints { get { return _pointCollection; } set { _pointCollection = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("TabPolygonPoints")); } } public string TabHeaderText { get { return _tabHeaderText; } set { _tabHeaderText = value; TabPolygonPoints = GenPolygon(); if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("TabHeaderText")); } } private PointCollection GenPolygon() { var w = new FormattedText(_tabHeaderText, CultureInfo.GetCultureInfo("en-us"), FlowDirection.LeftToRight, new Typeface("Tahoma"), 12, Brushes.Black); var width = w.Width + 30; _polygonPoints = new List(4); _pointCollection = new PointCollection(4); _polygonPoints.Add(new Point(2, 21)); _polygonPoints.Add(new Point(10, 2)); _polygonPoints.Add(new Point(width, 2)); _polygonPoints.Add(new Point(width + 8, 21)); foreach (var point in _polygonPoints) _pointCollection.Add(point); return _pointCollection; } } } 

Principal:

 namespace TrapezoidTab { ///  /// Interaction logic for MainWindow.xaml ///  public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); foreach (var obj in FruitTab.Items) { var tab = obj as TabItem; if (tab == null) continue; tab.DataContext = new TabHeaderViewModel(tab.Header.ToString()); } } } } 

Sí, puedes hacerlo; básicamente, todo lo que tienes que hacer es crear una plantilla de control personalizada. Consulte http://www.switchonthecode.com/tutorials/the-wpf-tab-control-inside-and-out para obtener un tutorial. Simplemente buscando en Google “wpf” “tabcontrol” “shape” aparece la página de resultados.

No he probado esto por mí mismo, pero debería poder reemplazar las tags en la plantilla con tags para obtener la forma que desea.