2010-10-01 32 views
6

Parece que WFP DataGridComboBoxColumn está utilizando un solo ItemsSource para todas las celdas en esta columna. Tengo un caso donde los elementos de ComboBox dependen de la otra celda en la misma fila. Logré poblar ItemsSource en el evento PreparingCellForEdit. Sin embargo, no funciona como se desea. Inicialmente, todas las celdas de esta columna están vacías. Una vez que llene el ItemsSource para ComboBox de esta columna, todas las celdas relacionadas (con la misma fuente de elementos) muestran los valores. Sin embargo, si hago clic en otro tipo de celda (se completa una fuente de elementos diferentes), todos los valores desaparecen y las nuevas celdas de tipo muestran valores. ¿Solo puede usar un conjunto de elementos de origen para una columna? No puedo creer que sea cierto. ¿Yo me perdí algo? Cualquier solución?Cómo obtener el nivel de celda ComboBox para WPF DataGrid?

Respuesta

1

Gracias al ejemplo de Jonathan, resolví mi problema de la siguiente manera. Modifiqué el código de Jonathan para resaltar mi solución. Eliminé la propiedad Territorio de su ejemplo porque no la necesito para mi problema.

Hay dos columnas. La primera columna es Estado. La segunda columna es StateCandidate. La columna de estado está vinculada a una lista de Estados, y la columna de StateCandidate está vinculada a una lista StateCandidates. El punto clave es que la lista StateCandidates se recrea cuando se cambia el estado. Por lo tanto, podría haber una lista diferente de StateCandidates en cada fila (en función del Estado seleccionado).

MainWindow.xaml

<Window x:Class="WpfTest1.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"> 
    <Grid> 
     <DataGrid Name="Zoom" AutoGenerateColumns="False" Background="DarkGray" RowHeaderWidth="50" HeadersVisibility="All"> 
      <DataGrid.Columns> 
       <DataGridTemplateColumn x:Name="colState" Header="State" Width="120"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding State}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
        <DataGridTemplateColumn.CellEditingTemplate> 
         <DataTemplate> 
          <ComboBox SelectedItem="{Binding State}" ItemsSource="{Binding States}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellEditingTemplate> 
       </DataGridTemplateColumn> 
       <DataGridTemplateColumn x:Name="colStateCandiate" Header="State Candidate" Width="200"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <TextBlock Text="{Binding StateCandidate}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
        <DataGridTemplateColumn.CellEditingTemplate> 
         <DataTemplate> 
          <ComboBox SelectedItem="{Binding StateCandidate}" ItemsSource="{Binding StateCandidates}" /> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellEditingTemplate> 
       </DataGridTemplateColumn> 
      </DataGrid.Columns> 
     </DataGrid> 
    </Grid> 
</Window> 

MainWindow.xaml.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.ComponentModel; 

namespace WpfTest1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      List<Model> list = new List<Model>(); 
      list.Add(new Model() { State = "TX", StateCandidate = "TX2" }); 
      list.Add(new Model() { State = "CA" }); 
      list.Add(new Model() { State = "NY", StateCandidate = "NY1" }); 
      list.Add(new Model() { State = "TX" }); 
      list.Add(new Model() { State = "AK" }); 
      list.Add(new Model() { State = "MN" }); 

      Zoom.ItemsSource = list; 
      Zoom.PreparingCellForEdit += new EventHandler<DataGridPreparingCellForEditEventArgs>(Zoom_PreparingCellForEdit); 
     } 

     void Zoom_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e) 
     { 
      if (e.Column == colStateCandiate) 
      {     
       DataGridCell cell = e.Column.GetCellContent(e.Row).Parent as DataGridCell; 
       cell.IsEnabled = (e.Row.Item as Model).StateCandidates != null; 
      } 
     } 
    } 
    public class Model : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     private string _state; 
     private List<string> _states = new List<string>() { "CA", "TX", "NY", "IL", "MN", "AK" }; 
     private string _stateCandidate; 
     private List<string> _stateCandidates; 

     public string State 
     { 
      get { return _state; } 
      set 
      { 
       if (_state != value) 
       { 
        _state = value; 
        _stateCandidate = null; 
        if (_state == "CA" || _state == "TX" || _state == "NY") 
         _stateCandidates = new List<string> { _state + "1", _state + "2" }; 
        else 
         _stateCandidates = null; 
        OnPropertyChanged("State"); 
       } 
      } 
     } 
     public List<string> States 
     { 
      get { return _states; } 
     } 
     public string StateCandidate 
     { 
      get { return _stateCandidate; } 
      set 
      { 
       if (_stateCandidate != value) 
       { 
        _stateCandidate = value; 
        OnPropertyChanged("StateCandidate"); 
       } 
      } 
     } 
     public List<string> StateCandidates 
     { 
      get { return _stateCandidates; } 
     } 
     public void OnPropertyChanged(string name) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(name)); 
     } 
    } 
} 

Tenga en cuenta que, cuando se cambia del estado, no se actualizará la lista StateCandidates hasta que se seleccione una fila diferente, que es un problema separado en el que estaré peleando. ¿Alguien sabe cómo puedo forzar el compromiso?

Gracias a Jonathan nuevamente por su inspiración. Seguiré buscando una mejor solución.

+0

Vas por el mismo camino a ninguna parte en la que estuve. Pero como insiste, aquí está el código: http://www.scottlogic.co.uk/blog/colin/tag/ieditableobject/ –

+2

@Jonathan: Muchas gracias por el enlace. Sin embargo, no pude hacer que funcione para esta muestra, tal vez porque no uso DataTable. Mientras luchaba con eso, encontré un comentario en ese blog que apunta a http://codefluff.blogspot.com/2010/05/commiting-bound-cell-changes.html. Esta solución funciona genial. – newman

+0

Mis aplicaciones, publiqué el enlace equivocado. No estoy usando una DataTable tampoco, tu enlace es realmente el que terminé usando. –

2

Probablemente no pueda hacerlo de manera confiable. La grilla puede reutilizar el cuadro combinado o crearlo/destruirlo al azar.

Por casualidad, estoy trabajando en una pantalla que hace precisamente eso. Teniendo en cuenta ...

  • Cada fila en la cuadrícula está vinculada a un objeto del tipo Comercio.
  • Cada comercio tiene una propiedad Estado
  • Cada comercio tiene una propiedad TerritoryCanidates
  • Cambio de la propiedad del Estado hará que los TerritoryCanidates propiedad para cambiar

Esto me da la capacidad de unirse al ItemsSource a los TerritoryCanidates propiedad. Que a su vez, DataGrid cumplirá bajo todas las circunstancias.


<Window x:Class="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"> 
<Grid> 
    <DataGrid Name="Zoom" AutoGenerateColumns="False"> 
     <DataGrid.Columns> 
      <DataGridTemplateColumn Header="State"> 
       <DataGridTemplateColumn.CellTemplate> 
        <DataTemplate> 
         <TextBlock Text="{Binding State}" /> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellTemplate> 
       <DataGridTemplateColumn.CellEditingTemplate> 
        <DataTemplate> 
         <ComboBox SelectedItem="{Binding State}" ItemsSource="{Binding StateCanidates}" /> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellEditingTemplate> 
      </DataGridTemplateColumn> 

      <DataGridTemplateColumn Header="Territory"> 
       <DataGridTemplateColumn.CellTemplate> 
        <DataTemplate> 
         <TextBlock Text="{Binding Territory}" /> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellTemplate> 
       <DataGridTemplateColumn.CellEditingTemplate> 
        <DataTemplate> 
         <ComboBox SelectedItem="{Binding Territory}" ItemsSource="{Binding TerritoryCanidates}" /> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellEditingTemplate> 
      </DataGridTemplateColumn> 

     </DataGrid.Columns> 

    </DataGrid> 
</Grid> 
</Window> 


Imports System.ComponentModel 

Class MainWindow 
Sub New() 

    ' This call is required by the designer. 
    InitializeComponent() 

    ' Add any initialization after the InitializeComponent() call. 
    Dim x As New List(Of Model) 
    x.Add(New Model) 
    x.Add(New Model) 
    x.Add(New Model) 

    Zoom.ItemsSource = x 
End Sub 
End Class 

Class Model 
Implements INotifyPropertyChanged 

Public ReadOnly Property StateCanidates As List(Of String) 
    Get 
     Return New List(Of String) From {"CA", "TX", "NY"} 
    End Get 
End Property 

Public ReadOnly Property TerritoryCanidates As List(Of String) 
    Get 
     If State = "" Then Return Nothing 
     Return New List(Of String) From {State & "1", State & "2"} 
    End Get 
End Property 

Private m_State As String 
Public Property State() As String 
    Get 
     Return m_State 
    End Get 
    Set(ByVal value As String) 
     m_State = value 
     OnPropertyChanged("State") 
     OnPropertyChanged("TerritoryCanidates") 
    End Set 
End Property 

Private m_Territory As String 
Public Property Territory() As String 
    Get 
     Return m_Territory 
    End Get 
    Set(ByVal value As String) 
     m_Territory = value 
     OnPropertyChanged("Territory") 
    End Set 
End Property 




Public Sub OnPropertyChanged(ByVal propertyName As String) 
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) 
End Sub 

Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged 
End Class 
+0

Estoy confundido ... ¿Funciona para ti? Lo probé y no pude hacerlo funcionar. Lo que probé es así: hice una nueva colección para ItemsSource para enlazar. Esta colección se volverá a crear cuando cambie otra propiedad. No veo nada en el menú desplegable desplegable. – newman

+0

Impar, parece que la columna del cuadro combinado no funciona como esperaba. Volví a hacer mi ejemplo usando columnas de plantilla como mis usos reales del programa. –

+1

P.S. Ahora odio oficialmente DataGrid para editar datos. En su lugar, solo voy a usar un ItemsControl. –

Cuestiones relacionadas