2009-09-23 15 views
7

Estoy creando una ventana WPF con DataGrid, y quiero mostrar la fila en blanco "nuevo elemento" en la parte inferior de la cuadrícula que me permite agregar un nuevo elemento a la cuadrícula. Por algún motivo, la fila en blanco no se muestra en la cuadrícula de mi ventana. Aquí está el marcado he utilizado para crear el DataGrid:WPF DataGrid: Falta fila en blanco

<toolkit:DataGrid x:Name="ProjectTasksDataGrid" 
        DockPanel.Dock="Top" 
        Style="{DynamicResource {x:Static res:SharedResources.FsBlueGridKey}}" 
        AutoGenerateColumns="False" 
        ItemsSource="{Binding SelectedProject.Tasks}" 
        RowHeaderWidth="0" 
        MouseMove="OnStartDrag" 
        DragEnter="OnCheckDropTarget" 
        DragOver="OnCheckDropTarget" 
        DragLeave="OnCheckDropTarget" 
        Drop="OnDrop" 
        InitializingNewItem="ProjectTasksDataGrid_InitializingNewItem"> 
    <toolkit:DataGrid.Columns> 
     <toolkit:DataGridCheckBoxColumn HeaderTemplate="{DynamicResource {x:Static res:SharedResources.CheckmarkHeaderKey}}" Width="25" Binding="{Binding Completed}" IsReadOnly="false"/> 
     <toolkit:DataGridTextColumn Header="Days" Width="75" Binding="{Binding NumDays}" IsReadOnly="false"/> 
     <toolkit:DataGridTextColumn Header="Due Date" Width="75" Binding="{Binding DueDate, Converter={StaticResource standardDateConverter}}" IsReadOnly="false"/> 
     <toolkit:DataGridTextColumn Header="Description" Width="*" Binding="{Binding Description}" IsReadOnly="false"/> 
    </toolkit:DataGrid.Columns> 
</toolkit:DataGrid> 

no puedo entender por qué la fila en blanco no se muestra. He intentado lo obvio (IsReadOnly="false", CanUserAddRows="True"), sin suerte. ¿Alguna idea de por qué la fila en blanco está deshabilitada? Gracias por tu ayuda.

Respuesta

4

Vincent Sibal ha publicado article describing what is required for adding new rows to a DataGrid. Hay bastantes posibilidades, y la mayoría de esto depende del tipo de colección que está utilizando para SelectedProject.Tasks.

Recomendaría asegurarse de que "Tareas" no sea una colección de solo lectura, y que admita una de las interfaces necesarias (mencionadas en el enlace anterior) para permitir que se agreguen elementos nuevos correctamente con DataGrid.

+3

En realidad, Tasks es un ObservableCollection . Hice un proyecto de prueba vinculando una cuadrícula de datos al mismo tipo de colección, y la fila en blanco está presente en la parte inferior de la cuadrícula. La publicación de blog de Vincent es buena, pero lo hace parecer como si tuviera que implementar IEditableObject, que no es el caso. Un DataGrid simple de vainilla, vinculado a un ObservableCollection , debe mostrar la fila en blanco. Ver http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx. –

+0

Muchas gracias que fue útil. Sinceramente. – Star

5

Finalmente volví a este. No voy a cambiar la respuesta aceptada (marca de verificación verde), pero aquí está la causa del problema:

Mi modelo de vista ajusta las clases de dominio para proporcionar la infraestructura que necesita WPF. Escribí un CodeProject article en el método de envoltura que uso, que incluye una clase de colección que tiene dos parámetros de tipo:

VmCollection<VM, DM> 

donde DM es una clase de dominio envuelto, y DM es la clase WPF que lo envuelve .

Supone que, por alguna extraña razón, tener el segundo parámetro de tipo en la clase de recopilación hace que WPF DataGrid deje de ser editable. La solución es eliminar el segundo parámetro de tipo.

No puedo decir por qué funciona, solo que sí. Espero que ayude a alguien más en el camino.

58

También debe tener un constructor predeterminado en el tipo de la colección.

+0

¡Gracias! Me había perdido eso. –

+4

Esta es la respuesta que debería haberse marcado>. <¡Gracias al usuario al azar! – mpen

+0

Sí, esta es la respuesta para el mismo problema que tuve. – Xenan

1

Agregue un artículo vacío a su ItemsSource y luego elimínelo. Es posible que deba volver a poner CanUserAddRows en true después de hacer esto. Leí esta solución here: (Publicaciones de Jarrey y Rick Roen)

Tuve este problema cuando configuré el ItemsSource en el DefaultView de un DataTable y la vista estaba vacía. Las columnas fueron definidas, por lo que debería haber sido capaz de obtenerlas. Je.

+0

Ugh. Gracias. Esto me ha estado volviendo absolutamente loco. Finalmente renuncié a las entidades y me mudé a conjuntos de datos tipeados e incluso * que * fallaron. El truco consiste en * asignar * la colección primero y * luego * manipularla agregando y eliminando un objeto. – Brett

5

En mi opinión, esto es un error en el DataGrid. Mike Blandford's link me ayudó a comprender finalmente cuál es el problema: DataGrid no reconoce el tipo de filas hasta que tiene un objeto real encuadernado. La fila de edición no aparece, porque la cuadrícula de datos no conoce los tipos de columna. Se podría pensar que vincular una colección fuertemente tipada funcionaría, pero no es así.

Para ampliar la respuesta de Mike Blandford, primero debe asignar la colección vacía y luego agregar y eliminar una fila.Por ejemplo,

private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     // data binding 
     dataGridUsers.ItemsSource = GetMembershipUsers(); 
     EntRefUserDataSet.EntRefUserDataTable dt = (EntRefUserDataSet.EntRefUserDataTable)dataGridUsers.ItemsSource; 
     // hack to force edit row to appear for empty collections 
     if (dt.Rows.Count == 0) 
     { 
      dt.AddEntRefUserRow("", "", false, false); 
      dt.Rows[0].Delete(); 
     } 
    } 
+0

¡Esto me sirvió! – Dan

0

Para mí la mejor manera de implementar asíncrono editable DataGrid parece que:

Ver Modelo:

public class UserTextMainViewModel : ViewModelBase 
{ 
    private bool _isBusy; 
    public bool IsBusy 
    { 
     get { return _isBusy; } 
     set 
     { 
      this._isBusy = value; 
      OnPropertyChanged(); 
     } 
    } 




    private bool _isSearchActive; 
    private bool _isLoading; 


    private string _searchInput; 
    public string SearchInput 
    { 
     get { return _searchInput; } 
     set 
     { 
      _searchInput = value; 
      OnPropertyChanged(); 

      _isSearchActive = !string.IsNullOrEmpty(value); 
      ApplySearch(); 
     } 
    } 

    private ListCollectionView _translationsView; 
    public ListCollectionView TranslationsView 
    { 
     get 
     { 
      if (_translationsView == null) 
      { 
       OnRefreshRequired(); 
      } 

      return _translationsView; 
     } 
     set 
     { 
      _translationsView = value; 
      OnPropertyChanged(); 
     } 
    } 


    private void ApplySearch() 
    { 
     var view = TranslationsView; 

     if (view == null) return; 

     if (!_isSearchActive) 
     { 
      view.Filter = null; 
     } 
     else if (view.Filter == null) 
     { 
      view.Filter = FilterUserText; 
     } 
     else 
     { 
      view.Refresh(); 
     } 
    } 

    private bool FilterUserText(object o) 
    { 
     if (!_isSearchActive) return true; 

     var item = (UserTextViewModel)o; 

     return item.Key.Contains(_searchInput, StringComparison.InvariantCultureIgnoreCase) || 
       item.Value.Contains(_searchInput, StringComparison.InvariantCultureIgnoreCase); 
    } 




    private ICommand _clearSearchCommand; 
    public ICommand ClearSearchCommand 
    { 
     get 
     { 
      return _clearSearchCommand ?? 
        (_clearSearchCommand = 
        new DelegateCommand((param) => 
        { 
         this.SearchInput = string.Empty; 

        }, (p) => !string.IsNullOrEmpty(this.SearchInput))); 
     } 
    } 

    private async void OnRefreshRequired() 
    { 
     if (_isLoading) return; 

     _isLoading = true; 
     IsBusy = true; 
     try 
     { 
      var result = await LoadDefinitions(); 
      TranslationsView = new ListCollectionView(result); 
     } 
     catch (Exception ex) 
     { 
      //ex.HandleError();//TODO: Needs to create properly error handling 
     } 

     _isLoading = false; 
     IsBusy = false; 
    } 


    private async Task<IList> LoadDefinitions() 
    { 
     var translatioViewModels = await Task.Run(() => TranslationRepository.Instance.AllTranslationsCache 
     .Select(model => new UserTextViewModel(model)).ToList()); 
     return translatioViewModels; 
    } 


} 

XAML:

<UserControl x:Class="UCM.WFDesigner.Views.UserTextMainView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:model="clr-namespace:Cellebrite.Diagnostics.Model.Entities;assembly=Cellebrite.Diagnostics.Model" 
     xmlns:System="clr-namespace:System;assembly=mscorlib" 
     xmlns:converters1="clr-namespace:UCM.Infra.Converters;assembly=UCM.Infra" 
     xmlns:core="clr-namespace:UCM.WFDesigner.Core" 
     mc:Ignorable="d" 
     d:DesignHeight="300" 
     d:DesignWidth="300"> 


<DockPanel> 
    <StackPanel Orientation="Horizontal" 
       DockPanel.Dock="Top" 
       HorizontalAlignment="Left"> 


     <DockPanel> 

      <TextBlock Text="Search:" 
         DockPanel.Dock="Left" 
         VerticalAlignment="Center" 
         FontWeight="Bold" 
         Margin="0,0,5,0" /> 

      <Button Style="{StaticResource StyleButtonDeleteCommon}" 
        Height="20" 
        Width="20" 
        DockPanel.Dock="Right" 
        ToolTip="Clear Filter" 
        Command="{Binding ClearSearchCommand}" /> 

      <TextBox Text="{Binding SearchInput, UpdateSourceTrigger=PropertyChanged}" 
        Width="500" 
        VerticalContentAlignment="Center" 
        Margin="0,0,2,0" 
        FontSize="13" /> 

     </DockPanel> 
    </StackPanel> 
    <Grid> 
     <DataGrid ItemsSource="{Binding Path=TranslationsView}" 
        AutoGenerateColumns="False" 
        SelectionMode="Single" 
        CanUserAddRows="True"> 
      <DataGrid.Columns> 
       <!-- your columns definition is here--> 
      </DataGrid.Columns> 
     </DataGrid> 
     <!-- your "busy indicator", that shows to user a message instead of stuck data grid--> 
     <Border Visibility="{Binding IsBusy,Converter={converters1:BooleanToSomethingConverter TrueValue='Visible', FalseValue='Collapsed'}}" 
       Background="#50000000"> 
      <TextBlock Foreground="White" 
         VerticalAlignment="Center" 
         HorizontalAlignment="Center" 
         Text="Loading. . ." 
         FontSize="16" /> 
     </Border> 
    </Grid> 
</DockPanel> 

Este patrón permite trabajar con la cuadrícula de datos de una manera bastante simple y el código es muy simple. No olvides crear el constructor predeterminado para la clase que representa tu fuente de datos.