wpf combobox tabcontrol

wpf - Controlar la pestaña activa de TabControl con un ComboBox



(4)

Lo que realmente intento lograr es controlar completamente el TabItem activo usando el cuadro combinado como control de navegación.

Esto es lo que he conseguido hasta ahora:

<TabControl Canvas.Left="26" Canvas.Top="27" Height="100" Name="TabControl1" Width="220"> <TabItem Header="TabItem1" x:Name="TabItem1"> <Grid /> </TabItem> <TabItem Header="TabItem2" x:Name="TabItem2"> <Grid /> </TabItem> </TabControl> <ComboBox Canvas.Left="126" Canvas.Top="134" Height="23" Name="CmbTabs" Width="120" ItemsSource="{Binding ElementName=TabControl1, Path=Items}" SelectedValue="{Binding ElementName=TabControl1, Path=SelectedIndex}" SelectedValuePath="TabIndex" DisplayMemberPath="Header"/>

Aún así, lo único que funciona realmente es la lista que aparece cuando presiono el botón de selección del cuadro combinado. Incluso seleccionando un nombre de tabitem a través de la lista no hace nada, ni siquiera actualiza el cuadro de texto de valor seleccionado del cuadro combinado.

Alguna ayuda ?

Editar: Ok, la respuesta de Steve Robbins funcionó bien para el problema de "control".

¿Qué pasa con el hecho de que seleccionar un elemento en la lista desplegable del cuadro combinado no actualiza el valor del cuadro combinado? (el cuadro de texto de cuadros combinados todavía está en blanco!)


Si estás tratando de controlar TabControl desde el Combo, parece un poco hacia atrás ... si cambias el SelectedIndex en el control de pestañas para vincularlo al combo, debería funcionar:

<TabControl Canvas.Left="26" Canvas.Top="27" Height="100" Name="TabControl1" Width="220" SelectedIndex="{Binding ElementName=CmbTabs, Path=SelectedIndex}"> <TabItem Header="TabItem1" x:Name="TabItem1"> <Grid /> </TabItem> <TabItem Header="TabItem2" x:Name="TabItem2"> <Grid /> </TabItem> </TabControl>


He estado jugando con esto mucho. Hay algo sobre el origen del cambio de enlace de datos de ComboBox después de realizar la selección. O algo.

Agregué el espacio de nombres de Diagnóstico:

xmlns:debug="clr-namespace:System.Diagnostics;assembly=WindowsBase"

Y cambié tu <Grid /> en TextBoxes con grandes números de bocina para que pudiera ver que las cosas realmente estaban cambiando:

<TabItem Header="TabItem1" x:Name="TabItem1"> <TextBlock Name="tb1" FontSize="24" Text="1" Width="100" Height="26" /> </TabItem>

Y cuando ejecuté la aplicación, descubrí que Diagnostics informa un resultado extraño:

Error de System.Windows.Data: 39: Error de ruta de BindingExpression: la propiedad ''Header'' no se encuentra en ''object'' '''' TextBlock ''(Name ='' tb1 ​​'')''. BindingExpression: Path = Header; DataItem = ''TextBlock'' (Name = ''tb2''); el elemento de destino es ''TextBlock'' (Name = ''''); la propiedad de destino es ''Texto'' (escriba ''Cadena'')

Intenté establecer el enlace de datos una vez, en código, al inicio:

public Window1() { InitializeComponent(); Binding positionBinding = new Binding("Items"); positionBinding.ElementName = "TabControl1"; positionBinding.Path = new PropertyPath("Items"); positionBinding.Mode = BindingMode.OneTime; CmbTabs.SetBinding(ComboBox.ItemsSourceProperty, positionBinding); CmbTabs.DisplayMemberPath = "Header"; }

Y aún cambia el CombobBox para mostrar ningún elemento seleccionado después de la selección y el cambio de TabItem. Es como si el DataContext fuera cambiado a TabControl.TabItem.TextBlock después de que TabControl cambia la selección.

Así que no tengo exactamente una respuesta para ti, pero tengo algunos resultados para que trabajes.

Bea Stollnitz tiene un buen artículo sobre el uso de esta técnica de diagnóstico. "¿Cómo puedo depurar enlaces WPF?"


Partiendo de la respuesta de hughdbrown, encontré esta publicación en MSDN que describe su problema como un error. Puede reproducirlo con este XAML (que tiene el problema opuesto al de su XAML):

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <TabControl Name="TabControl1" Width="220" Height="100" Canvas.Left="26" Canvas.Top="27"> <TabItem x:Name="TabItem1" Header="TabItem1"> foobar </TabItem> <TabItem x:Name="TabItem2" Header="TabItem2"> fizzbuzz </TabItem> </TabControl> <ComboBox Name="CmbTabs" Width="120" Height="23" Canvas.Left="126" Canvas.Top="134" ItemsSource="{Binding ElementName=TabControl1, Path=Items}" DisplayMemberPath="Length" SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}"/> </Canvas>

Como puede ver, el enlace Longitud funciona bien, excepto en el menú desplegable, donde se va fuera del TabItem en lugar de dentro de la cadena.

No estoy seguro de que sea ideal para sus propósitos, pero puede evitarlo siendo un poco menos elegante y reproduciendo sus encabezados en ComboBoxItems:

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <TabControl Name="TabControl1" Width="220" Height="100" Canvas.Left="26" Canvas.Top="27"> <TabItem x:Name="TabItem1" Header="TabItem1"> <Grid/> </TabItem> <TabItem x:Name="TabItem2" Header="TabItem2"> <Grid/> </TabItem> </TabControl> <ComboBox Name="CmbTabs" Width="120" Height="23" Canvas.Left="126" Canvas.Top="134" SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}"> <ComboBoxItem>TabItem1</ComboBoxItem> <ComboBoxItem>TabItem2</ComboBoxItem> </ComboBox> </Canvas>


Empecé a ver esto debido a algunos problemas que estoy teniendo con el cuadro combinado. Lamentablemente, no he resuelto mi problema, pero puedo proporcionar información adicional y una solución alternativa a este problema. Primero, comencemos con mis cambios al xaml original.

<TabControl Height="100" Name="TabControl1" Width="220"> <TabItem Header="TabItem1" x:Name="TabItem1"> <TextBlock Text="TabItem1 Content" /> </TabItem> <TabItem Header="TabItem2" x:Name="TabItem2"> <TextBlock Text="TabItem2 Content" /> </TabItem> </TabControl> <ComboBox Height="23" Name="CmbTabs" Width="120" ItemsSource="{Binding ElementName=TabControl1, Path=Items}" SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}" DisplayMemberPath="Name" > </ComboBox>

Tenga en cuenta que en lugar de crear un enlace desde el control de pestañas al ComboBox y viceversa, podemos crear un enlace de TwoWay (el valor predeterminado en este caso) entre el SelectedIndex de la pestaña y los controles combinados. A continuación, agreguemos algo de contenido a los TabItems. En este punto, similar a la sugerencia de Steve, hemos solucionado el problema de "control". Es decir, cambiar el TabItem seleccionado cambia el elemento ComboBox seleccionado (¡tendrá que confiar en mí en este caso o seguir leyendo!) Y cambiar el ComboBox cambia el TabItem seleccionado. ¡Estupendo!

El xaml anterior también cambia la propiedad DiplayMemberPath a "Nombre". Creo que descubrirás que esto elimina el "extraño resultado" de hughdbrown. Recuerde que la propiedad Header (un objeto) está envuelta por un ContentPresenter. Creo que si no se proporciona una plantilla, el comportamiento predeterminado es mostrar el objeto de encabezado como una cadena en un TextBlock. Por lo tanto, el "resultado extraño" informa correctamente de que el control TextBlock no contiene una propiedad de encabezado.

Ahora hagamos algunos cambios al ComboBox xaml anterior.

<ComboBox Height="23" Name="CmbTabs" Width="120" ItemsSource="{Binding ElementName=TabControl1, Path=Items}" SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}" > <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"/> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>

Esto realmente produce un resultado interesante y hace uso del contenido que agregamos a cada TabItem. Cuando se ejecuta este código, notará que el ComboBox ahora muestra el contenido del TabItem seleccionado. Además, la lista ahora muestra "System.Windows.Controls.TabItem ..." para cada TabItem. Podemos cambiar el enlace de TextBlock a {Encuadernación de encabezado} y mostrar el objeto de encabezado, pero el ComboBox aún muestra el contenido seleccionado de TabItem. Como es tarde un viernes por la noche y simplemente no hay suficiente cerveza en el mundo, no busqué las posibles razones para esto. Sin embargo, ¡tengo una solución alternativa!

Primero, creemos un ValueConverter para convertir la colección Items de TabControl a algo que podamos usar. Aquí está el código.

public class TabItemCollectionConverter : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ItemCollection collection = value as ItemCollection; IList<string> names = new List<string>(); foreach (TabItem ti in collection.SourceCollection) { names.Add(ti.Header.ToString()); } return names; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } #endregion }

El convertidor simplemente crea una nueva colección de la colección Items de TabControl que contiene el objeto de encabezado string -ized de cada TabItem. Esto funciona bien para objetos simples de encabezado, pero obviamente tiene limitaciones. Ahora consideremos cómo usamos esto en el xaml.

<ComboBox Height="23" Name="CmbTabs" Width="120" ItemsSource="{Binding ElementName=TabControl1, Path=Items, Converter={StaticResource ItemConverter}}" SelectedIndex="{Binding ElementName=TabControl1, Path=SelectedIndex}" > <ComboBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"/> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox>

Recuerde que un ValueConverter utilizado en un enlace ItemsSource devuelve una nueva colección. En este caso, estamos convirtiendo la colección Elementos de TabControl en una colección de cadenas. ¡No olvides crear el convertidor StaticResource! Se ve algo como esto.

<local:TabItemCollectionConverter x:Key="ItemConverter"/>

Ahora, usando el convertidor, toda la bola de cera funciona como se esperaba.

Lo que todavía me desconcierta es por qué el ComboBox muestra los encabezados TabItem en la lista y el contenido TabItem como la selección. Sin duda hay alguna explicación obvia, pero como dije, es viernes ...

¡Espero que esto ayude!