Quiero mostrar algo de contenido personalizado (usando la plantilla de datos) al hacer clic en el botón:
<ContentControl x:Name="content" />
<Button Content="Test" Click="button_Click" />
El botón muestra / oculta contenido como este
VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
content.Content = content.Content == null ? _vm : null;
Aquí está la plantilla de datos:
<DataTemplate DataType="{x:Type local:VM}">
<ListBox ItemsSource="{Binding Items}" SelectionChanged="listBox_SelectionChanged">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</DataTemplate>
Controlador de eventos:
void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
Title = "Items: " + ((ListBox)sender).Items.Count;
Viewmodel:
public class VM
{
public List<Item> Items { get; } = new List<Item> { new Item(), new Item(), new Item() };
}
public class Item
{
public bool IsSelected { get; set; }
}
El problema : cuando la plantilla de datos se descarga, SelectionChanged
para el evento ListBox
se eleva sin elementos.
No quiero este evento. No quiero ver "Elementos: 0" después de seleccionar algo y descargar la plantilla de datos.
Pregunta : ¿qué está sucediendo y cómo puedo evitar que esto suceda?
Nota: esto es MCVE muy corto y simplificado, es decir, no todo es bonito, aunque hay puntos clave: plantilla de datos con ListBox
dentro, que usa el enlace IsSelected
y necesito deshacerme de eso {{X2 }} evento en la descarga.
Pila de llamadas:
3 respuestas
Esto funciona exactamente como se diseñó. Hizo una selección haciendo clic en un elemento en el cuadro de lista. Cuando la plantilla se descarga, el enlace ItemsSource
se desconecta y el origen de los elementos se vacía. En ese momento, la selección actual ya no es válida (el elemento no existe en el origen de los elementos), por lo que la selección se borra. Eso es un cambio de selección: la selección pasó de algo a nada. El evento se espera se generará en estas circunstancias.
Rara vez es necesario suscribirse a SelectionChanged
. Por lo general, es mejor vincular el SelectedItem
a una propiedad en su modelo de vista. Cada vez que cambie la selección, esa propiedad se actualizará. En lugar de responder al evento SelectionChanged
, puede responder a ese cambio de propiedad.
Este enfoque evita muy bien el problema que está viendo. Una vez que se descargue la plantilla, el enlace SelectedItem
se desconectará, por lo que su modelo de vista ya no se actualizará. En consecuencia, no verá ese cambio final cuando se borre la selección.
Solución alternativa para múltiples selecciones.
Si su ListBox
admite múltiples selecciones, puede continuar suscribiéndose a SelectionChanged
. Sin embargo, no consulte listBoxItems
; en su lugar, escanee a través de _vm.Items
y vea qué elementos tienen IsSelected
configurados en true
. Eso debería indicarle la selección real, y los resultados no deberían verse afectados por la descarga de la plantilla.
También puede determinar que la plantilla se descargó verificando si (sender as ListBox)?.ItemsSource
es nulo en su controlador. Sin embargo, esto no debería ser necesario.
Creo que esto está ocurriendo porque siempre está sobrescribiendo el contenido:
VM _vm = new VM();
void button_Click(object sender, RoutedEventArgs e) =>
content.Content = content.Content == null ? _vm : null;
Cámbielo a esto para que la lista solo se asigne una vez, de modo que solo se asigne una vez.
void button_Click(object sender, RoutedEventArgs e)
{
if (content.Content == null )
{
content.Content = _vm;
// I also recommend you add the event handler for the ListBox here so it's not fired until you have content.
}
}
Creo que listBox_SelectionChanged
cuando descargas la lista este evento se dispara, porque la sección realmente cambió, verifica el recuento de elementos allí, y si es 0 establece el título como predeterminado.
void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
Title = (((ListBox)sender).Items.Count > 0)? "Items: " + ((ListBox)sender).Items.Count: "Your title";
Nuevas preguntas
c#
C # (pronunciado "see sharp") es un lenguaje de programación multi-paradigma de alto nivel, estáticamente tipado desarrollado por Microsoft. El código C # generalmente se dirige a la familia de herramientas y tiempos de ejecución .NET de Microsoft, que incluyen .NET Framework, .NET Core y Xamarin, entre otros. Use esta etiqueta para preguntas sobre el código escrito en las especificaciones formales de C # o C #.