2010-01-06 17 views
27

¿Alguien puede ayudarme con lo siguiente? He estado jugando con esto pero no puedo por mi vida hacer que funcione.WPF vinculante a Listbox selectedItem

Tengo un modelo de vista que contiene las siguientes propiedades;

public ObservableCollection<Rule> Rules { get; set; } 
public Rule SelectedRule { get; set; } 

En mi XAML tengo;

<ListBox x:Name="lbRules" ItemsSource="{Binding Path=Rules}" 
     SelectedItem="{Binding Path=SelectedRule, Mode=TwoWay}"> 
<ListBox.ItemTemplate> 
    <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Text="Name:" /> 
       <TextBox x:Name="ruleName"> 
        <TextBox.Text> 
         <Binding Path="Name" UpdateSourceTrigger="PropertyChanged" /> 
        </TextBox.Text> 
       </TextBox> 
      </StackPanel> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

Ahora el ItemsSource funciona bien y me da una lista de Regla objetos con sus nombres que aparecen en lbRules.

Problema que estoy teniendo está vinculando la propiedad SelectedRule a lbRules 'SelectedItem. Intenté vincular la propiedad de texto de un bloque de texto a SelectedRule, pero siempre es nulo.

<TextBlock Text="{Binding Path=SelectedRule.Name}" /> 

El error que estoy viendo en la ventana de salida es: error de ruta BindingExpression: no se encontró la propiedad 'SelectedRule'.

¿Alguien me puede ayudar con este enlace? No puedo ver por qué no debería encontrar la propiedad SelectedRule.

Intenté cambiar la propiedad de texto del bloque de texto como de abajo, que funciona. El problema es que quiero usar SelectedRule en mi ViewModel.

<TextBlock Text="{Binding ElementName=lbRules, Path=SelectedItem.Name}" /> 

Muchas gracias por su ayuda.

Respuesta

24

en primer lugar, es necesario implementar INotifyPropertyChanged interfaz en su modelo de vista y provocar el evento PropertyChanged en la incubadora de la propiedad Rule. de lo contrario no tiene control que se une a la propiedad SelectedRule se "saber" cuando se ha sido cambiado.

Luego, su XAML

<TextBlock Text="{Binding Path=SelectedRule.Name}" /> 

es perfectamente válido si esto está fuera del TextBlockListBox 's ItemTemplate y tiene el mismo DataContext como el ListBox.

+0

Eso es todo, tonto, no había implementado la interfaz en ese modelo de vista. ¡Golpeé mi cabeza contra la pared toda la mañana en eso! Muchas gracias por su ayuda. También muchas gracias a todos los demás, especialmente a Yacoder, por tomarse el tiempo para echar un vistazo a esto. –

+0

Gracias de mí también. Solo tenía el problema exacto. Implementé la interfaz pero olvidé plantear el evento. –

10

Dentro de la DataTemplate que está trabajando en el contexto de un Rule, es por eso que no se puede unir a SelectedRule.Name - No hay tal propiedad en un Rule. para enlazar con el contexto de datos original (que es su modelo de vista) se puede escribir:

<TextBlock Text="{Binding ElementName=lbRules, Path=DataContext.SelectedRule.Name}" /> 

ACTUALIZACIÓN: con respecto a la unión de la propiedad SelectedItem, parece perfectamente válido, he intentado lo mismo en mi máquina y funciona multa. Aquí está mi aplicación plena prueba:

XAML:

<Window x:Class="TestWpfApplication.ListBoxSelectedItem" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="ListBoxSelectedItem" Height="300" Width="300" 
    xmlns:app="clr-namespace:TestWpfApplication"> 
    <Window.DataContext> 
     <app:ListBoxSelectedItemViewModel/> 
    </Window.DataContext> 
    <ListBox ItemsSource="{Binding Path=Rules}" SelectedItem="{Binding Path=SelectedRule, Mode=TwoWay}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <StackPanel Orientation="Horizontal"> 
        <TextBlock Text="Name:" /> 
        <TextBox Text="{Binding Name}"/> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Window> 

Código atrás:

namespace TestWpfApplication 
{ 
    /// <summary> 
    /// Interaction logic for ListBoxSelectedItem.xaml 
    /// </summary> 
    public partial class ListBoxSelectedItem : Window 
    { 
     public ListBoxSelectedItem() 
     { 
      InitializeComponent(); 
     } 
    } 


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

    public class ListBoxSelectedItemViewModel 
    { 
     public ListBoxSelectedItemViewModel() 
     { 
      Rules = new ObservableCollection<Rule>() 
      { 
       new Rule() { Name = "Rule 1"}, 
       new Rule() { Name = "Rule 2"}, 
       new Rule() { Name = "Rule 3"}, 
      }; 
     } 

     public ObservableCollection<Rule> Rules { get; private set; } 

     private Rule selectedRule; 
     public Rule SelectedRule 
     { 
      get { return selectedRule; } 
      set 
      { 
       selectedRule = value; 
      } 
     } 
    } 
} 
+0

Gracias por ambas respuestas. Veo lo que quiere decir, pero no estoy seguro si lo entiendo completamente. El problema es que DataTemplate funciona bien: entiendo que el contexto dentro de la plantilla es la Regla. Es el enlace del SelectedItem de lbRules a mi propiedad SelectedRule con el que estoy teniendo problemas. ¿Estás diciendo que al configurar ItemSource también estoy configurando indirectamente el DataContext del listbox? Lo siento si no lo dejé claro. Solo estaba usando el enlace a un bloque de texto para ayudarme a solucionar el problema. –

+0

He actualizado mi respuesta. –

+0

Muchas gracias por su respuesta. Tu respuesta me ha resultado muy útil para llegar a mi solución. Resultó que mi problema era que no estaba implementando InotifyPropertyChanged y es por eso que marqué la respuesta de Arconaut como respuesta. Gracias por su tiempo. Sin embargo, una cosa que me interesa es la razón por la que su solución no implementa la interfaz INotifyPropertyChanged pero aún funciona ... De todos modos, gracias de nuevo por su tiempo. –

3

Yocoder es correcto,

Dentro de la DataTemplate, su DataContext se establece en el Rule su actualmente manejando ..

Para acceder a los padres DataContext, también se puede considerar el uso de un RelativeSource en su unión:

<TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ____Your Parent control here___ }}, Path=DataContext.SelectedRule.Name}" /> 

Más información sobre RelativeSource se puede encontrar aquí:

http://msdn.microsoft.com/en-us/library/system.windows.data.relativesource.aspx

-6

ya que se establece su itemource para su colección, su cuadro de texto está vinculado a cada elemento individual en esa colección. la propiedad del elemento seleccionado es útil en este escenario si estaba tratando de hacer un formulario de detalles maestros, con 2 cuadros de lista. vinculará el origen de elementos del segundo listbox al conjunto de reglas hijo. en otras palabras, el elemento seleccionado alerta fuera de los controles que su fuente ha cambiado, los controles internos (los que están dentro de su plantilla de datos ya están al tanto del cambio.

y para responder a su pregunta sí, en la mayoría de los casos, configurar el origen de la fuente es igual que configurar el DataContext del control.

+3

"establecer el origen de los artículos es lo mismo que configurar el contexto de datos del control" - por favor no publique tonterías :) – arconaut

0

Para mí, normalmente utilizo DataContext para unir propiedades de dos profundidades como esta pregunta.

<TextBlock DataContext="{Binding SelectedRule}" Text="{Binding Name}" />

O, yo prefiero usar ElementName porque logra únicamente con fijaciones de controles de vista.

<TextBlock DataContext="{Binding ElementName=lbRules, Path=SelectedItem}" Text="{Binding Name}" />