Cómo implementar DataGridComboBoxColumn editable en WPF DataGrid
binding (3)
Intente utilizar SelectedValue solo, pero junto con él use DisplayMemberPath y TextSearch.TextPath.
<ComboBox IsEditable="True" DisplayMemberPath="MyDisplayProperty" SelectedValuePath="MyValueProperty" SelectedValue="{Binding MyViewModelValueProperty}" TextSearch.TextPath="MyDisplayProperty" />
Para los cuadros combinados editables debemos sincronizar qué valor selecciona el combo, qué valor muestran los elementos y qué valor debemos buscar en función de la entrada del usuario.
Pero si está utilizando una colección de cadenas para enlazar su cuadro combinado, entonces puede intentar seguir ...
Agregue una nueva propiedad en su ViewModel llamada InstrumentsView. Esto devuelve un nuevo ListCollectionView.
public static string ListCollectionView InstrumentsView { get { return new ListCollectionView(Instruments); } }
Cambie su DataGridComboBoxColumn XAML de la siguiente manera ...
<DataGridComboBoxColumn Header="Instrument" MinWidth="140" ItemsSource="{x:Static ViewModel.InstrumentsView}"> <DataGridComboBoxColumn.EditingElementStyle> <Style TargetType="ComboBox"> <Setter Property="IsEditable" Value="True"/> <Setter Property="IsSynchronizedWithCurrentItem" Value=True" /> <Setter Property="SelectedItem" Value="{Binding SelectedInstrument, Mode=OneWayToSource}" /> <!-- Assuming that SelectedInstrument is string --> </Style> </DataGridComboBoxColumn.EditingElementStyle> </DataGridComboBoxColumn>
Dime si esto funciona ...
Quiero permitir al usuario editar algunos datos en WPF DataGrid (desde .net Framework 4.0). La columna "instrumentos" debe permitir al usuario seleccionar un instrumento disponible de una lista estática o escribir un texto libre. Mi DataGrid se enlaza a los datos mediante MVVM. He probado muchas soluciones que he encontrado en internet, pero ninguna de ellas funciona correctamente. Aquí está mi código:
<DataGrid Margin="0,6" ItemsSource="{Binding Path=Orders}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="True">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Instrument" MinWidth="140"
ItemsSource="{x:Static ViewModel.Instruments}" SelectedItemBinding="{Binding Path=SelectedInstrument}">
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="IsEditable" Value="True"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
La lista desplegable se muestra correctamente. El campo se puede editar con cualquier texto, pero establece un valor nulo en SelectedInstrument después de que se cierre el menú desplegable para el texto libre. Funciona solo para el elemento seleccionado. He intentado cambiar a SelectedValueBinding, pero no ayuda.
¿Cómo implementar estos requisitos correctamente? ¿Puede alguien publicar aquí una muestra de trabajo?
Adicional : Las órdenes son ObservableCollection La orden tiene propiedad como el título de la cadena, DateTime Ordered, string SelectedInstrument, Instruments es una cadena []
Soluciones : A continuación se sugiere como una solución de los trabajos de bathineni :
<DataGrid Margin="0,6" ItemsSource="{Binding Path=Orders}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Instrument" MinWidth="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=SelectedInstrument, Mode=OneWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="True" Text="{Binding Path=SelectedInstrument}"
ItemsSource="{x:Static ViewModel.Instruments}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Puede crear su propio tipo de columna ComboBox subclasificando DataGridBoundColumn
. En comparación con la solución de subclasificación de DataGridTemplateColumn
bathineni, la solución a continuación tiene el beneficio de una mejor experiencia de usuario (sin doble tabulación) y tiene más opciones para ajustar la columna a sus necesidades específicas.
public class DataGridComboBoxColumn : DataGridBoundColumn {
public Binding ItemsSourceBinding { get; set; }
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
var textBox = new TextBlock();
BindingOperations.SetBinding(textBox, TextBlock.TextProperty, Binding);
return textBox;
}
protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) {
var comboBox = new ComboBox { IsEditable = true };
BindingOperations.SetBinding(comboBox, ComboBox.TextProperty, Binding);
BindingOperations.SetBinding(comboBox, ComboBox.ItemsSourceProperty, ItemsSourceBinding);
return comboBox;
}
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs) {
var comboBox = editingElement as ComboBox;
if (comboBox == null) return null;
comboBox.Focus(); // This solves the double-tabbing problem that Nick mentioned.
return comboBox.Text;
}
}
A continuación, puede utilizar el componente por ejemplo como este.
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding MyItems}">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<local:DataGridComboBoxColumn Header="Thingy" Binding="{Binding Thingy}"
ItemsSourceBinding="{Binding
RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}},
Path=Thingies}"/>
</DataGrid.Columns>
</DataGrid>
Obtuve esta solución siguiendo esta respuesta a una pregunta similar.
esto sucede porque el texto libre que se ingresa es de tipo cadena y el elemento seleccionado, lo que ha enlazado con el comboBox es de algún tipo complejo ...
en lugar de usar DataGridComboBoxColumn
use DataGridTemplateColumn
y puede enlazar la propiedad Text
del comboBox a alguna propiedad que mantendrá el valor del texto libre después de cerrar la lista desplegable.
Puedes tener una mejor idea mirando la siguiente muestra.
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox IsEditable="True"
Text="{Binding NewItem}"
ItemsSource="{Binding Sourcelist.Files}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>