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
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.
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
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
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. –
P.S. Ahora odio oficialmente DataGrid para editar datos. En su lugar, solo voy a usar un ItemsControl. –
- 1. WPF DataGrid ComboBox causa InvalidOperationException
- 2. WPF toolkit datagrid texto de celda envoltura
- 3. Actualice WPF DataGrid sin perder el foco de celda
- 4. WPF DataGrid cómo obtener cuando ItemsSource actualiza
- 5. Cambio de FlowDirection de una celda en DataGrid de Wpf
- 6. WPF actualización de fuente de DataGrid en la celda modificada
- 7. WPF datagrid Color de la celda según el valor de la celda preivous
- 8. WPF DataGrid - Establecer una celda en modo de edición programáticamente
- 9. Ventana emergente de WPF en la celda DataGrid MouseOver
- 10. Enlazar entradas a DataGrid ComboBox View
- 11. Mover el foco a la siguiente celda al presionar la tecla Entrar ¿WPF DataGrid?
- 12. Cómo copiar el valor de celda DataGrid al portapapeles
- 13. WPF - ¿Cómo obtener una celda de un DataGridRow?
- 14. WPF Datagrid: evento SelectionChanged no se produce cuando SelectionUnit = "Celda"
- 15. Estilo WPF DataGrid-Silverlight DataGrid?
- 16. ¿Cómo establecer maxlength para combobox en WPF?
- 17. Cómo implementar DataGridComboBoxColumn editable en WPF DataGrid
- 18. WPF: copia de un DataGrid
- 19. desplazamiento suave para WPF DataGrid
- 20. WPF datagrid con MVVM
- 21. ¿Cómo se borra una celda (para que tenga valor NULL) en (WPF) DataGrid?
- 22. Cómo cambiar el estilo de ComboBox de celda en DataGridViewComboBoxColumn
- 23. ¿Cómo manejar el evento Wpf DataGrid CellEditEnding en MVVM?
- 24. C#/WPF: Encuadernación Combobox ItemSource en Datagrid con el elemento exterior de la DataContext
- 25. WPF DataGrid: ¿cómo puedo detener el desplazamiento automático cuando se hace clic en una celda?
- 26. WPF Toolkit DataGrid Multi-Select: ¿Cómo obtener Selected Items out?
- 27. WPF arrastre y suelte en DataGrid
- 28. WPF Combobox DisplayMemberPath
- 29. WPF: ComboBox TextSearch, ¿cómo funciona?
- 30. elemento en ComboBox WPF
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/ –
@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
Mis aplicaciones, publiqué el enlace equivocado. No estoy usando una DataTable tampoco, tu enlace es realmente el que terminé usando. –