2011-04-01 18 views
26

He visto las respuestas a variousquestions, pero no he logrado asignar el contenido en las respuestas al problema que estoy tratando de resolver. Lo he reducido al siguiente código (representativo del resultado que estoy tratando de lograr), y básicamente quiero poder representar el Person.TitleId como su correspondiente Title.TitleText cuando la fila no está siendo editada, y tengo la caída -down bound correctamente para que muestre el TitleText s en el menú desplegable y escribe el TitleId asociado de nuevo en el registro Person cuando se modificó.Enlazando un WGT DataGridComboBoxColumn con MVVM

En resumen, ¿qué pongo en mi <DataGridComboBoxColumn> para lograr esto?

App.xaml.cs

protected override void OnStartup(StartupEventArgs e) 
{ 
    base.OnStartup(e); 

    var viewModel = new ViewModels.MainWindowViewModel(); 
    var mainWindow = new MainWindow(); 
    mainWindow.DataContext = viewModel; 
    mainWindow.ShowDialog(); 
} 

MainWindow.xaml

<Grid> 
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=Contacts}"> 
     <DataGrid.Columns> 
      <DataGridComboBoxColumn Header="Title" SelectedItemBinding="{Binding Person}"> 
       <DataGridComboBoxColumn.ElementStyle> 
        <Style TargetType="ComboBox"> 
         <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
         <Setter Property="IsReadOnly" Value="True"/> 
        </Style> 
       </DataGridComboBoxColumn.ElementStyle> 
       <DataGridComboBoxColumn.EditingElementStyle> 
        <Style TargetType="ComboBox"> 
         <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
         <Setter Property="DisplayMemberPath" Value="TitleText" /> 
        </Style> 
       </DataGridComboBoxColumn.EditingElementStyle> 
      </DataGridComboBoxColumn> 
     </DataGrid.Columns> 
    </DataGrid> 
</Grid> 

Person.cs

public class Person 
{ 
    public int TitleId { get; set; } 
    public string LastName { get; set; } 
    public string FirstName { get; set; } 
} 

Title.cs

public struct Title 
{ 
    public Title(int titleId, string titleText) 
     : this() 
    { 
     TitleId = titleId; 
     TitleText = titleText; 
    } 

    public string TitleText { get; private set; } 
    public int TitleId { get; private set; } 

    public static List<Title> GetAvailableTitles() 
    { 
     var titles = new List<Title>(); 

     titles.Add(new Title(1, "Mr")); 
     titles.Add(new Title(2, "Miss")); 
     titles.Add(new Title(3, "Mrs")); 

     return titles; 
    } 
} 

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase 
{ 
    private ObservableCollection<Person> contacts; 
    private List<Title> titles; 

    public MainWindowViewModel() 
    { 
     titles = Title.GetAvailableTitles(); 

     Contacts = new ObservableCollection<Person>(); 
     Contacts.Add(new Person() { FirstName = "Jane", LastName = "Smith", TitleId = 2 }); 
    } 

    public List<Title> Titles 
    { 
     get { return titles; } 
    } 

    public ObservableCollection<Person> Contacts 
    { 
     get { return contacts; } 
     set 
     { 
      if (contacts != value) 
      { 
       contacts = value; 
       this.OnPropertyChanged("Contacts"); 
      } 
     } 
    } 
} 

ViewModelBase.cs

public class ViewModelBase : INotifyPropertyChanged 
{ 
    protected void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 
+0

Ayudaría si pudiera delinear qué partes de ese 'plan' no funcionan/cuáles realmente funcionan. p.ej. ¿puede ubicar la lista de ItemsSource de ComboBox? –

+0

También: Desde el aspecto de cómo se usa 'Title', la clase parece redundante y sería mejor que fuera reemplazada por un' Dictionary '. –

+0

@ H.B. - A medida que el código permanece, la cuadrícula no muestra la representación textual del valor inicial (es decir, el TitleText apropiado para Person.TitleId), el menú desplegable se llena con {Mr, Mrs, Miss} correctamente y seleccionando un elemento en el resultados desplegables en TestMVVM.Models.Título que se muestra en la cuadrícula (TestMVVM.Models es el espacio de nombres en la solución, que eliminé por brevedad). – Rob

Respuesta

35

Aquí hay un código de trabajo. El punto clave aquí fue usar SelectedValueBinding en lugar de SelecteItemBinding.

<DataGridComboBoxColumn Header="Title" 
         SelectedValueBinding="{Binding TitleId}" 
         SelectedValuePath="TitleId" 
         DisplayMemberPath="TitleText" 
         > 
    <DataGridComboBoxColumn.ElementStyle> 
     <Style TargetType="ComboBox"> 
      <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
     </Style> 
    </DataGridComboBoxColumn.ElementStyle> 
    <DataGridComboBoxColumn.EditingElementStyle> 
     <Style TargetType="ComboBox"> 
      <Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Titles}"/> 
     </Style> 
    </DataGridComboBoxColumn.EditingElementStyle> 
</DataGridComboBoxColumn> 
+0

Increíble, estaba escribiendo casi exactamente lo mismo, bueno, esta ronda va para ti. –

+0

esto funciona perfectamente en mi caso reducido, voy a dedicar algo de tiempo a integrarlo en mi código real para ver si funciona allí (¡estoy seguro de que lo hará!). ¿Alguna posibilidad de que me expliques * cómo/por qué * funciona? :) – Rob

+2

'SelectedValuePath' establece la ruta al miembro dentro del objeto seleccionado que representa el elemento seleccionado del ComboBox,' DisplayMemberPath' por el otro establece la ruta al miembro dentro de la clase que debe mostrarse. El 'SelectedValueBinding' vinculará el valor seleccionado a la propiedad especificada en el enlace. Es un poco confuso pero si lo usa algunas veces tiene sentido. E: http://stackoverflow.com/questions/3797034/confused-with-wpf-combobox-displaymemberpath-selectedvalue-and-selectedvaluepath –

2

@ La respuesta de SnowBear funcionó bien para mí. Pero quiero aclarar un detalle de la unión.

En el ejemplo de @ Rob, las clases Título y Persona usan TitleID. Por lo tanto, en la respuesta de @ SnowBear, en la unión:

SelectedValueBinding="{Binding TitleId}" 

no fue inmediatamente obvio para mí, que la clase y la propiedad estaba siendo obligado.

Como el atributo SelectedValueBinding apareció en DataGridComboBoxColumn, es vinculante para ItemsSource del DataGrid que lo contiene. En este caso, la colección Contactos de objetos Persona.

En mi caso, se le atribuyó a la colección DataSource de DataGrid una propiedad con un nombre diferente al ValuePath de la colección ItemSource de ComboBox. Por lo tanto, mi valor de SelectedValueBinding estaba ligado a una propiedad diferente a la propiedad nombrada en SelectedValuePath de ComboBox.

Cuestiones relacionadas