2012-02-02 31 views
5

Tengo un DataGrid al que un usuario puede agregar elementos ingresando datos en la última fila. También tengo un botón que elimina el elemento seleccionado actualmente. Pero cuando se selecciona la última fila (vacía, para agregar nuevos elementos), lo que fuera el último elemento seleccionado permanece en SelectedItem. Por lo tanto, si abro la ventana, selecciono la última fila y presiono el botón Eliminar, eliminará la primera fila, ya que está seleccionada de manera predeterminada, y la selección de la última fila no modificó SelectedItem. ¿Alguna buena forma de lidiar con esto?WPF DataGrid SelectedItem

Para aclarar: SelectedItem = "{X} Encuadernación"

X en el modelo de vista no cambia cuando se selecciona la última fila (la incubadora no se invoca en absoluto). No estoy seguro de si la propiedad SelectedItem en sí misma cambia, pero supongo que no.

También hay una excepción cuando selecciono la última fila (borde rojo), pero cuando vuelvo a hacer clic para comenzar a ingresar datos, el borde rojo desaparece. No estoy seguro si estos dos están relacionados.

Respuesta

10

Ejecute el siguiente ejemplo y verá por qué no funciona.

XAML:

<Window x:Class="DataGridTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <DockPanel> 
     <TextBlock DockPanel.Dock="Bottom" Text="{Binding SelectedItem, ElementName=dataGrid}"/> 
     <TextBlock DockPanel.Dock="Bottom" Text="{Binding SelectedItem}"/> 
     <DataGrid x:Name="dataGrid" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" CanUserAddRows="True" CanUserDeleteRows="True" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/> 
       <DataGridTextColumn Header="Last Name" Binding="{Binding FirstName}"/> 
      </DataGrid.Columns> 
     </DataGrid> 
    </DockPanel> 
</Window> 

de código subyacente:

namespace DataGridTest 
{ 
    using System.Collections.Generic; 
    using System.Collections.ObjectModel; 
    using System.ComponentModel; 
    using System.Windows; 

    public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     private readonly ICollection<Person> items; 
     private Person selectedItem; 

     public MainWindow() 
     { 
      InitializeComponent(); 

      this.items = new ObservableCollection<Person>(); 
      this.items.Add(new Person 
       { 
        FirstName = "Kent", 
        LastName = "Boogaart" 
       }); 
      this.items.Add(new Person 
      { 
       FirstName = "Tempany", 
       LastName = "Boogaart" 
      }); 

      this.DataContext = this; 
     } 

     public ICollection<Person> Items 
     { 
      get { return this.items; } 
     } 

     public Person SelectedItem 
     { 
      get { return this.selectedItem; } 
      set 
      { 
       this.selectedItem = value; 
       this.OnPropertyChanged("SelectedItem"); 
      } 
     } 

     private void OnPropertyChanged(string propertyName) 
     { 
      var handler = this.PropertyChanged; 

      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 

    public class Person 
    { 
     public string FirstName 
     { 
      get; 
      set; 
     } 

     public string LastName 
     { 
      get; 
      set; 
     } 

     public override string ToString() 
     { 
      return FirstName + " " + LastName; 
     } 
    } 
} 

Como se puede ver cuando se ejecuta, la selección de la fila "nueva" provoca un valor centinela que se fijará como el elemento seleccionado en el DataGrid. Sin embargo, WPF no puede convertir ese artículo de centinela a Person, por lo que el enlace SelectedItem no puede convertirse.

Para solucionar esto, puede poner un convertidor en su encuadernación que detecta el centinela y devuelve null cuando se detecta. Aquí está un convertidor que no lo hace:

namespace DataGridTest 
{ 
    using System; 
    using System.Windows.Data; 

    public sealed class SentinelConverter : IValueConverter 
    { 
     public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      return value; 
     } 

     public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
     { 
      if (value != null && string.Equals("{NewItemPlaceholder}", value.ToString(), StringComparison.Ordinal)) 
      { 
       return null; 
      } 

      return value; 
     } 
    } 
} 

Como se puede ver, se trata de una desafortunada necesidad para poner a prueba frente al valor ToString() del centinela, porque es un tipo interno. Alternativamente, podría (o además) verificar que GetType().Name sea NamedObject.

+2

5 años después, pero también podría ponerlo aquí: puede compararlo con CollectionView.NewItemPlaceholder, que es lo mismo que está haciendo, sin la necesidad de grabar la cadena "{NewItemPlaceholder}" en su código. –

0

Difícil de decir sin código, pero me gustaría ver lo siguiente.

Asegúrese de que cada vez que se elimine un elemento y también sea el elemento seleccionado, establezca el elemento seleccionado vinculado a la propiedad en su ViewModel como nulo. Deberá asegurarse de que su SelectedItem vinculado a la propiedad no esté vinculado de una sola vez.

0

Parece que olvidó establecer el Modo vinculante y el valor predeterminado está configurado en OneWay. Lo que significa que cualquier cambio realizado en su vista no se propagará de nuevo a su modelo de vista.

Y siempre asegúrese de tener el contexto de datos correcto.

Espero que ayude.