2010-01-28 14 views
7

Ok, he estado trabajando con WPF por un tiempo, pero necesito ayuda.WPF ComboBox SelectedItem

Tengo un ComboBox, como a continuación:

<TabControl> 
    <TabItem Header="1"> 
     <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/> 
    </TabItem> 
    <TabItem Header="2"/> 
</TabControl> 

Cada vez que me alejo de ficha 1 y luego volver a la selección que se retira. Creo que la razón es que los controles se destruyen cuando salen del alcance y vuelven a entrar. Pero en el proceso de que el SelectedItem sea nulo, lo cual no es realmente lo que el usuario quería, es un evento debido a la interfaz de usuario. ciclo vital.

Así que me pregunto cuál es la mejor ruta para tomar? Estoy compilando esta aplicación con MVVM para poder ignorar una llamada establecida en la Propiedad MyListSelection en mi ViewModel pero tengo ComboBoxes por todas partes y no me gusta modificar mi ViewModel por lo que considero un error de WPF.

Pude subclase el WPF ComboBox, pero no hay evento SelectedItemChanging. Solo puedo agregar un controlador cuando SelectedItem haya cambiado.

¿Alguna idea?

ACTUALIZACIÓN:

bien, después de vencer a la cabeza contra la pared descubrí por qué mi problema No se pudo obtener reproducido. Si el tipo de elemento de la lista es una clase por alguna razón, WPF establece que SelectedItem sea nulo, pero si es un tipo de valor no lo hace.

aquí es mi clase de prueba (VMBase es sólo una clase abstracta que implementa INotifyPropertyChanged):

public class TestListViewModel : VMBase 
{ 
    public TestListViewModel() 
    { 
     TestList = new List<TestViewModel>(); 
     for (int i = 0; i < 10; i++) 
     { 
      TestList.Add(new TestViewModel(i.ToString())); 
     } 
    } 

    public List<TestViewModel> TestList { get; set; } 

    TestViewModel _SelectedTest; 
    public TestViewModel SelectedTest 
    { 
     get { return _SelectedTest; } 
     set 
     { 
      _SelectedTest = value; 
      OnPropertyChanged("SelectedTest"); 
     } 
    } 
} 

public class TestViewModel : VMBase 
{ 
    public string Name {get;set;} 
} 

Así que cuando cambio TestList de tipo int e ir y venir entre las pestañas SelectedItem se mantiene igual. Pero cuando es del tipo TestViewModel SelectedTest se establece en nulo cuando el tabitem se desenfoca.

¿Qué está pasando?

Respuesta

10

Tengo exactamente el mismo problema, y ​​hasta ahora no podía entender cuál es el problema. Probé en 4 máquinas diferentes con las mismas especificaciones de sistema operativo, .Net y hardware, y pude reproducir el problema en dos de ellas, en las otras funcionó bien. La solución alternativa que pude encontrar que funciona para mí es definir el enlace SelectedItem antes de ItemsSource. Extrañamente si sigo este patrón, todo funciona como se esperaba. Dicho esto, sólo hay que hacer lo siguiente:

<Window x:Class="ComboBoxInTabItemSpike.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <TabControl> 
      <TabItem Header="1"> 
       <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/> 
      </TabItem> 
      <TabItem Header="2"/> 
     </TabControl> 
     <TextBlock Text="{Binding MySelect}"/> 
    </StackPanel> 
</Window> 
0

EDITADO después del cambio en OP. Hola José, no puedo reproducir el error que mencionas. Entonces su suposición de que el Control está siendo destruido está mal. Combobox se comporta como se esperaba con el código que se muestra a continuación, incluso ahora está utilizando un tipo de referencia. Alguna otra parte de tu código debe activarse cuando cambias TabItems.

<Window x:Class="ComboBoxInTabItemSpike.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <TabControl> 
      <TabItem Header="1"> 
       <ComboBox ItemsSource="{Binding MyList}" 
          SelectedItem="{Binding MySelect}"/> 
      </TabItem> 
      <TabItem Header="2"/> 
     </TabControl> 
     <TextBlock Text="{Binding MySelect}"/> 
    </StackPanel> 
</Window> 

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Windows; 

namespace ComboBoxInTabItemSpike 
{ 
    public partial class Window1 : Window, INotifyPropertyChanged 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
      MyList=new ObservableCollection<TestObject>(
       new[]{new TestObject("1"),new TestObject("2"),new TestObject("3") }); 
      DataContext = this; 
     } 

     public ObservableCollection<TestObject> MyList { get; set; } 

     private TestObject mySelect; 
     public TestObject MySelect 
     { 
      get { return mySelect; } 
      set{ mySelect = value; 
      if(PropertyChanged!=null) 
       PropertyChanged(this,new PropertyChangedEventArgs("MySelect"));} 
     } 

     public TestObject MySelectedItem 
     { 
      get { return (TestObject)GetValue(MySelectedItemProperty); } 
      set { SetValue(MySelectedItemProperty, value); } 
     } 

     public static readonly DependencyProperty MySelectedItemProperty = 
      DependencyProperty.Register("MySelectedItem", 
           typeof(TestObject), 
           typeof(Window1), 
           new UIPropertyMetadata(null)); 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 

    public class TestObject 
    { 
     public string Name { get; set; } 

     public TestObject(string name) 
     { 
      Name = name; 
     } 

     public override string ToString() 
     { 
      return Name; 
     } 
    } 
} 
+1

Cuando el Tipo de lista es un tipo de referencia, no se comporta igual. Ver mi publicación actualizada – Jose

0

Recomendaría revisar las fijaciones. Si alguna otra cosa en su aplicación está cambiando el elemento seleccionado o la fuente de los elementos, su enlace se romperá. También puede buscar en Visual Studio en la ventana de resultados para ver si hay algún error.

0

Creo que lo que puede faltar aquí es un enlace TwoWay en el elemento seleccionado. Cuando vincula su clase ViewModel que contiene MyList (ItemsSource enlazado) y MyListSelection (Bond a SelectedItem en su caso) siempre tendrá esa información aunque haya accedido a pestañas diferentes. Entonces, cuando regrese a esta pestaña, MyListSelection se vinculará de nuevo al ComboBoc.SelectedItem y estará bien. Intenta eso y dejame saber.

+1

El enlace de SelectedItem es TwoWay por defecto. –

0

Creo que esto podría resolverse con un simple cheque nulo.

public TestViewModel SelectedTest 
{ 
    get { return _SelectedTest; } 
    set 
    { 
     if(value != null) 
      _SelectedTest = value; 
     OnPropertyChanged("SelectedTest"); 
    } 
} 

Esto se debe a cuadro combinado tiene una tendencia a restablecer su SelectedIndex cuando se reciclan. Esta simple comprobación nula obligará a volver a enlazar con el último elemento válido.

+0

Sí, esa es una opción que he empleado muchas veces, pero la aplicación tiene muchos cuadros combinados y listas de selección, es bastante molesto hacer eso siempre. – Jose

+0

De hecho, esto podría ser bastante molesto, pero volver a tener que subir la propiedad cambiado incluso en cada propiedad también es molesto. WPF está lejos de ser perfecto. GL –

+1

Esto no siempre es aceptable ya que los valores nulos a veces pueden ser valores válidos dentro de una colección. Además, ¿qué ocurre con los casos en los que la propiedad es en realidad una propiedad de dependencia? Entonces tendrías que mirar los eventos de Notificación de coerción y cambio para hacer algo similar, lo cual es un desastre. En mi opinión, esta no es una solución aceptable en general. – jpierson

0

que estaba teniendo el mismo problema con un tipo de referencia en mi lista. La solución fue anular Equals() en mi TestViewModel para que WPF pudiera hacer una comprobación de igualdad de valores (en lugar de una verificación de referencia) entre los objetos para determinar cuál es el SelectedItem. El mío tenía un campo de identificación que era realmente la característica de identificación de un TestViewModel.

0

Este comportamiento por el cuadro combinado, debe ser implementado por el compilador de una mejor manera que es ... IE el compilador debe verificar y ver si los tipos para ItemsSource y el tipo valor de referencia de la propiedad que SelectedItem está obligado a tendrá que devolver el valor que es comparable

se debe advertir a que usted podría considerar anulando los Iguales() y GetHashCode) métodos (...

perdido mucho tiempo en esto hoy !!