2011-08-01 69 views
14

Quiero que el usuario pueda editar algunos datos en WPF DataGrid (de .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 está enlazado a datos usando MVVM. He intentado muchas soluciones que he encontrado en Internet, pero ninguna de ellas funciona correctamente. Aquí está mi código:Cómo implementar DataGridComboBoxColumn editable en WPF DataGrid

<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> 

se muestra correctamente el-down-lista desplegable. El campo se puede editar con cualquier texto, pero establece un valor nulo para SelectedInstrument después de que se cierre el menú desplegable para el texto libre. Funciona solo para el elemento seleccionado. Intenté cambiar a SelectedValueBinding, pero no ayuda.

¿Cómo implementar estos requisitos correctamente? ¿Alguien puede publicar aquí una muestra de trabajo?

adicional: pedidos es ObservableCollection Orden tiene la propiedad como el título de cuerdas, DateTime Ordenado, SelectedInstrument cadena, Instruments es una cadena []

Soluciones: Siguiendo sugieren como una solución de bathineni obras :

<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> 
+0

Creo que en su solución debe reemplazar ' Neil

+0

DataGridTemplateColumn' sí, esto es errata –

Respuesta

13

esto está sucediendo porque el texto libre que es entrar es de tipo cadena y elemento seleccionado lo que ha vinculado al comboBox es de algún tipo complejo ...

en lugar de usar DataGridComboBoxColumn use DataGridTemplateColumn y puede enlazar la propiedad Text de comboBox a alguna propiedad que contendrá el valor de texto libre después de cerrar la lista desplegable.

puede obtener 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> 
+0

Gracias, funciona bien si agrego también

+4

This es una experiencia de usuario horrible Debe tabular una vez en esta columna y luego tabular una segunda vez en el cuadro combinado. Todas las otras columnas en la cuadrícula de datos solo requieren 1 pestaña, esta requiere presionar la pestaña dos veces. – Nick

5

Intente utilizar SelectedValue solamente pero junto con él use DisplayMe mberPath y TextSearch.TextPath.

<ComboBox IsEditable="True" DisplayMemberPath="MyDisplayProperty" SelectedValuePath="MyValueProperty" SelectedValue="{Binding MyViewModelValueProperty}" TextSearch.TextPath="MyDisplayProperty" /> 

Para cuadros combinados editables hay que sincronizar qué valor selecciona el combo, ¿qué valor la pantalla artículos y qué valor debemos búsqueda basada en la entrada del usuario.

Pero Si está utilizando un conjunto de cadenas para vincular a su cuadro combinado a continuación, puede seguir los siguientes pasos ...

  1. añadir una nueva propiedad en su modelo de vista llamado InstrumentsView. Esto devuelve un nuevo ListCollectionView.

    public static string ListCollectionView InstrumentsView 
    { 
         get 
         { 
           return new ListCollectionView(Instruments); 
         } 
    } 
    
  2. Cambie su DataGridComboBoxColumn XAML como a continuación ...

    <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 ....

+0

¿Estás decir para cambiar DataGridComboBoxColumn.EditingElementStyle o para usar en lugar de la DataGridTemplateColumn DataGridComboBoxColumn? Y mi objeto no tiene subpropiedades como MyValueProperty, porque es una cadena. –

+0

Consulte mi respuesta editada anteriormente con una nueva solución posible para la recopilación de cadenas. –

+0

If SelectedInstrument {get {return InstrumentView.CurrentItem; }} ¿cómo puedo implementar set para inicializar la vista inicial? CurrentItem es de solo lectura. –

2

Usted puede crear su propio tipo de columna ComboBox subclase DataGridBoundColumn.En comparación con la solución de bathineni de subclasificación DataGridTemplateColumn, la solución siguiente tiene el beneficio de una mejor experiencia del 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; 
    } 
} 

Puede utilizar el componente, por ejemplo, de esta manera.

<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> 

que tiene esta solución siguiendo this answer a una pregunta similar.