wpf mvvm combobox

WPF MVVM ComboBox SelectedItem o SelectedValue no funciona



wpf combobox selectionchanged (17)

Actualizar

Después de investigar un poco. Lo que parece ser el problema es que SelectedValue / SelectedItem está ocurriendo antes de que la fuente del artículo termine de cargarse. Si me siento en un punto de quiebre y espero unos segundos, funciona como se esperaba. No sé cómo voy a sortear este.

Fin de actualización

Tengo una aplicación que se usa en WPF usando MVVM con un ComboBox. A continuación se muestra el ejemplo de ViewModel. El problema que tengo es que cuando salimos de nuestra página y migramos, el ComboBox no está seleccionando el valor actual que está seleccionado.

Ver modelo

public class MyViewModel { private MyObject _selectedObject; private Collection<Object2> _objects; private IModel _model; public MyViewModel(IModel model) { _model = model; _objects = _model.GetObjects(); } public Collection<MyObject> Objects { get { return _objects; } private set { _objects = value; } } public MyObject SelectedObject { get { return _selectedObject; } set { _selectedObject = value; } } }

Por el bien de este ejemplo, digamos que MyObject tiene dos propiedades (Texto e Id). Mi XAML para el ComboBox se ve así.

XAML

<ComboBox Name="MyComboBox" Height="23" Width="auto" SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}" ItemsSource="{Binding Objects}" DisplayMemberPath="Text" SelectedValuePath="Id">

No importa de qué manera configure esto cuando regrese a la página y el objeto se reensamble, el ComboBox no seleccionará el valor. Sin embargo, el objeto devuelve el objeto correcto a través del get en la propiedad.

No estoy seguro de si esto es solo un problema con la forma en que funcionan los patrones ComboBox y MVVM. El enlace del cuadro de texto que estamos haciendo funciona correctamente.


¿Ha intentado implementar INotifyPropertyChanged en su viewmodel, y luego elevar el evento PropertyChanged cuando se establece el SelectedItem ?

Si esto en sí mismo no lo soluciona, podrá levantar manualmente el evento PropertyChanged usted mismo cuando navegue de regreso a la página, y eso debería ser suficiente para que WPF se rediseñe y muestre el elemento seleccionado correcto.


Al salir de la página actual, se ItemsSource CollectionView asociado con la propiedad ItemsSource del ComboBox . Y dado que la propiedad ComboBox IsSyncronizedWithCurrent es verdadera de manera predeterminada, las propiedades SelectedItem y SelectedValue se restablecen.
Esto parece ser un problema de tipo de datos internos en el enlace. Como otros sugirieron anteriormente, si usa SelectedValue lugar de enlazar a una propiedad int en el modelo de vista, funcionará. Un atajo para usted sería anular el operador Equals en MyObject para que al comparar dos MyObjects, se comparen las propiedades reales de Id .

Otra sugerencia: si reestructura sus modelos de vista y usa SelectedValue , utilícelos solo cuando SelectedValuePath=Id donde Id es int . Si usa una clave de cadena, vincule a la propiedad Text del ComboBox lugar de SelectedValue .


ComboBox.SelectionBoxItem.ToString ()


Debe colocar la propiedad ItemsSource ANTES de la propiedad SelectedItem. Me encontré con un blog hace unos días mencionando el problema.


El tipo de SelectedValuePath y SelectedValue debe ser EXACTAMENTE el mismo.

Si, por ejemplo, el tipo de SelectedValuePath es Int16 y el tipo de propiedad que se une a SelectedValue es int , no funcionará.

Paso horas para encontrar eso, y es por eso que estoy respondiendo aquí después de tanto tiempo la pregunta fue hecha. Tal vez otro pobre tipo como yo con el mismo problema pueda verlo.


En este caso, el enlace de elemento seleccionado no funciona, porque el identificador hash de los objetos es diferente.

Una posible solución es:

En función del ID del elemento seleccionado, recupere el objeto en la colección de fuentes de artículos y establezca con él la propiedad del elemento seleccionado.

Ejemplo:

<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />

La propiedad atada a ItemSource es:

public ObservableCollection<Profile> Profiles { get { return this.profiles; } private set { profiles = value; RaisePropertyChanged("Profiles"); } }

La propiedad enlazada a SelectedItem es:

public Profile SelectedProfile { get { return selectedProfile; } set { if (this.SelectedUser != null) { this.SelectedUser.Profile = value; RaisePropertyChanged("SelectedProfile"); } } }

El código de recuperación es:

[Command("SelectionChanged")] public void SelectionChanged(User selectedUser) { if (selectedUser != null) { if (selectedUser is User) { if (selectedUser.Profile != null) { this.SelectedUser = selectedUser; this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault(); MessageBroker.Instance.NotifyColleagues("ShowItemDetails"); } } } }

Espero que te ayude. Pasé mucho tiempo buscando respuestas, pero no pude encontrar.


Establecer IsSynchronizedWithCurrentItem="True" funcionó para mí!


Estuve peleando con este problema por un tiempo. En mi caso, estaba usando el tipo complejo (Lista) como Origen del artículo y estaba usando un Tipo de clave como el valor seleccionado. En el evento de carga, el KeyType se estableció en nulo. Esto causó que todo se rompiera. Ninguno de los subelementos se actualizaría cuando cambiara la clave. Resultó que cuando agregué un cheque para asegurarme de que el valor propuesto para KeyType no era nulo, todo funcionó como se esperaba.

#region Property: SelectedKey // s.Append(string.Format("SelectedKey : {0} " + Environment.NewLine, SelectedKey.ToString())); private KeyType _SelectedKey = new KeyType(); public KeyType SelectedKey { get { return _SelectedKey; } set { if(value != null ) if (!_SelectedKey.Equals(value)) { _SelectedKey = value; OnPropertyChanged("SelectedKey"); } } } #endregion SelectedKey


He tenido problemas similares y se resolvió asegurándome de que estaba implementando IEquatable correctamente. Cuando se produce la vinculación, se intenta ver si los objetos coinciden, así que asegúrese de implementar correctamente su comprobación de igualdad.


IsSyncronizedWithCurrent = False lo hará funcionar.


Podría ser la forma en que aplica el DataContext a la página. En WPF, cada vez que navegas hacia una página todo se reinicializa, se llama al constructor, se cargan métodos, todo. entonces, si está configurando su DataContext dentro de su Vista, sin duda estará eliminando ese SelectedItem que el usuario seleccionó. Para evitar eso use la propiedad KeepAlive de sus páginas.

<Page KeepAlive="True" ...> ... </Page>

Esto dará como resultado que solo se active el evento Loaded cuando navegue de regreso a una página que ya ha visitado. Por lo tanto, deberá asegurarse de configurar el DataContext en Initialize (ya sea de forma externa o dentro del constructor) en lugar de Load.

Sin embargo, esto solo funcionará para esa instancia de la página. Si navega a una nueva instancia de esa página, se volverá a llamar al constructor.


Resolví el problema agregando el despachador en el evento UserControl_Loaded

Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => { combobox.SelectedIndex = 0; }));


También he notado este comportamiento antes. Me di cuenta de que la propiedad SelectedIndex no causa el mismo error. Si puede reestructurar su ViewModel para exponer el índice del elemento seleccionado y vincularlo, debería estar listo.


Tengo una respuesta muy simple para este problema. Primero agregue el siguiente código a la vista IsSynchronizedWithCurrentItem = "True".

Luego, cada vez que asigne un objeto nuevo en ViewModel, esa propiedad SelectedObject se debe guardar en esa propiedad y no en el miembro privado.

El modelo de vista de Proptery debería verse así

public Role SelectedObject { get { return object; } set { if (value != null) { if (!object.Equals(value)) { object = value; OnPropertyChanged(() => SelectedObject ); } } } }

Esto debería solucionar el problema.


Tuve este problema con un ComboBox que muestra una lista de colores (Lista <Pincel>).
La selección de un color era posible, pero no se mostró cuando se cerró la selección (¡aunque se cambió la propiedad!)

La corrección sobrescribía el método Equals (obj de objeto) para el tipo seleccionado en ComboBox (Brush), que no era simple porque Brush está sellado. Así que escribí una clase EqualityBrush que contenía un Pincel e implementaba Equals:

public class EqualityBrush { public SolidColorBrush Brush { get; set; } public override bool Equals(object o) { if (o is EqualityBrush) { SolidColorBrush b = ((EqualityBrush)o).Brush; return b.Color.R == this.Brush.Color.R && b.Color.G == this.Brush.Color.G && b.Color.B == this.Brush.Color.B; } else return false; } }

Usar una lista de mi nueva clase EqualityBrush en lugar de la clase normal de Brush solucionó el problema.

Mi Combobox XAML se ve así:

<ComboBox ItemsSource="{Binding BuerkertBrushes}" SelectedItem="{Binding Brush, Mode=TwoWay}" Width="40"> <ComboBox.Resources> <DataTemplate DataType="{x:Type tree:EqualityBrush}"> <Rectangle Width="20" Height="12" Fill="{Binding Brush}"/> </DataTemplate> </ComboBox.Resources> </ComboBox>

Recuerda que mi propiedad "Brush" en ViewModel ahora tiene que ser de tipo EqualityBrush.


Use el evento cargado:

private void cmb_Loaded(object sender, RoutedEventArgs e) { if (cmb.Items.Count > 0) cmb.SelectedIndex = 0; }

Esto funciona para mi.


Yo tuve el mismo problema. La cosa es. El elemento seleccionado no sabe qué objeto debería usar de la colección. Por lo tanto, debe decirle al elemento seleccionado que use el elemento de la colección.

public MyObject SelectedObject { get { Objects.find(x => x.id == _selectedObject.id) return _selectedObject; } set { _selectedObject = value; } }

Espero que esto ayude.