2009-09-23 16 views
7

Tworzę okno WPF z DataGrid i chcę pokazać pusty wiersz "nowego przedmiotu" na dole siatki, który pozwala mi dodać nowy element do siatki. Z jakiegoś powodu pusty wiersz nie jest wyświetlany na siatce w moim oknie. Oto markup kiedyś stworzyć DataGrid:WPG DataGrid: Pusty wiersz Brakujący

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

nie mogę dowiedzieć się, dlaczego pusty wiersz nie jest wyświetlana. Wypróbowałem oczywiste rzeczy (IsReadOnly="false", CanUserAddRows="True"), bez powodzenia. Masz pomysł, dlaczego pusty wiersz jest wyłączony? Dzięki za pomoc.

Odpowiedz

4

Vincent Sibal opublikował article describing what is required for adding new rows to a DataGrid. Istnieje wiele możliwości, a większość zależy od rodzaju kolekcji, której używasz do SelectedProject.Tasks.

Zalecam, aby upewnić się, że "Zadania" nie jest zbiorem tylko do odczytu, i że obsługuje on jeden z wymaganych interfejsów (wymienionych w poprzednim łączu), aby umożliwić poprawne dodawanie nowych elementów do DataGrid.

+3

W rzeczywistości Zadania to ObservableCollection . Zrobiłem projekt testowy wiążący siatkę danych do tego samego rodzaju kolekcji, a pusty wiersz znajduje się na dole siatki. Post na blogu Vincenta jest dobry, ale sprawia, że ​​brzmi to tak, jakbyś musiał zaimplementować IEditableObject, co nie jest prawdą. Prosta wanilia DataGrid, powiązana z ObservableCollection , powinna wyświetlać pusty wiersz. Zobacz http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx. –

+0

Dziękuję bardzo, że było pomocne. Z poważaniem. – Star

5

Wreszcie wróciłem do tego. Nie zmieniam zaakceptowanej odpowiedzi (zielony znacznik wyboru), ale tutaj jest przyczyna problemu:

Mój widok model owija klasy domen, aby zapewnić infrastrukturę potrzebną w WPF. Napisałem CodeProject article o metodę oblewania używam, która zawiera klasę kolekcji, która ma dwa parametry Typ:

VmCollection<VM, DM> 

gdzie DM jest zawinięty klasy domeny, a DM jest klasa WPF, który owija go .

To zmywa, że ​​z jakiegoś dziwnego powodu posiadanie drugiego parametru typu w klasie kolekcji powoduje, że DataGrid WPF staje się nieedytowalna. Poprawka ma na celu wyeliminowanie drugiego parametru typu.

Nie mogę powiedzieć, dlaczego to działa, tylko że tak. Mam nadzieję, że pomaga komuś innemu w drodze.

58

Musisz także mieć domyślny konstruktor na typie w kolekcji.

+0

Dzięki! Tęskniłem za tym. –

+4

To jest odpowiedź, która powinna być zaznaczona>. mpen

+0

Tak, to jest odpowiedź na ten sam problem, który miałem. – Xenan

1

Dodaj pusty przedmiot do swojego ItemsSource, a następnie go usuń. Po wykonaniu tej czynności może być konieczne ustawienie wartości CanUserAddRows na true. Przeczytałem to rozwiązanie here: (Posty Jarrey i Rick Roen)

Miałem ten problem, gdy ustawiłem ItemsSource na DefaultView DataTable i widok był pusty. Kolumny zostały jednak zdefiniowane, więc powinny były je uzyskać. Heh.

+0

Ugh. Dzięki. To doprowadzało mnie do szaleństwa. W końcu zrezygnowałem z encji i przeszedłem do wpisanych zestawów danych, a nawet * to * zawiodło. Sztuczka polega na tym, aby najpierw przydzielić * kolekcję i * następnie * manipulować nią, dodając i usuwając obiekt. – Brett

5

Moim zdaniem jest to błąd w DataGrid. Mike Blandford's link pomógł mi w końcu uświadomić sobie, na czym polega problem: DataGrid nie rozpoznaje typu wierszy, dopóki nie zostanie powiązany z rzeczywistym obiektem. Wiersz edycji nie pojawia się b/c siatka danych nie zna typów kolumn. Można by pomyśleć, że wiązanie mocno typowanej kolekcji zadziała, ale tak nie jest.

Aby rozwinąć odpowiedź Mike Blandforda, musisz najpierw przypisać pustą kolekcję, a następnie dodać i usunąć wiersz.Na przykład,

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

To mi się udało! – Dan

0

Dla mnie najlepszym sposobem wdrożenia edycji asynchroniczne DataGrid wygląda tak:

Zobacz Model:

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> 

Ten wzór pozwala na pracę z siatką danych w dość prosty sposób, a kod jest bardzo prosty. Nie zapomnij o utworzeniu domyślnego konstruktora dla klasy reprezentującej twoje źródło danych.

Powiązane problemy