2009-09-23 12 views
7

Ich erstelle ein WPF-Fenster mit einem DataGrid, und ich möchte die leere Zeile "neues Element" am unteren Rand des Rasters anzeigen, die es mir erlaubt, ein neues Element zum Raster hinzuzufügen. Aus irgendeinem Grund wird die leere Zeile nicht im Raster auf meinem Fenster angezeigt. Hier ist die Auszeichnungs ich verwendet, um die DataGrid:WPF DataGrid: Leere Zeile fehlt

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

ich kann nicht herausfinden, warum die leere Zeile zeigt nicht. Ich habe das offensichtliche Zeug (IsReadOnly="false", CanUserAddRows="True") versucht, ohne Glück. Irgendeine Idee warum die leere Zeile deaktiviert ist? Danke für Ihre Hilfe.

Antwort

4

Vincent Sibal veröffentlichte eine article describing what is required for adding new rows to a DataGrid. Es gibt einige Möglichkeiten, und das meiste hängt davon ab, welche Art von Sammlung Sie für SelectedProject.Tasks verwenden.

Ich würde empfehlen, sicherzustellen, dass "Tasks" keine schreibgeschützte Sammlung ist und dass es eine der erforderlichen Schnittstellen (im vorherigen Link erwähnt) unterstützt, damit neue Elemente ordnungsgemäß mit DataGrid hinzugefügt werden können.

+3

Eigentlich Tasks ist eine ObservableCollection . Ich habe ein Testprojekt durchgeführt, bei dem ein Datenraster an dieselbe Art von Sammlung gebunden wurde. Die leere Zeile befindet sich am unteren Rand des Rasters. Vincents Blogbeitrag ist gut, aber er macht es so, als müsste man IEditableObject implementieren, was nicht der Fall ist. Ein normales DataGrid, das an eine ObservableCollection gebunden ist, sollte die leere Zeile anzeigen. Siehe http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx. –

+0

Vielen Dank, das war hilfreich. Mit freundlichen Grüßen. – Star

5

Endlich zurück zu diesem. Ich werde die akzeptierte Antwort nicht ändern (grünes Häkchen), aber hier ist die Ursache des Problems:

Mein Ansichtsmodell umschließt Domänenklassen, um die von WPF benötigte Infrastruktur bereitzustellen. Ich schrieb ein CodeProject article auf der Wrap-Methode, die ich verwende, die eine Sammlung Klasse umfasst, die zwei Typen Parameter:

VmCollection<VM, DM> 

wo DM eine Domain-Klasse eingewickelt sind, und DM ist die WPF-Klasse, die es hüllt .

Es führt aus, dass der WPF DataGrid aus irgendeinem seltsamen Grund, da der zweite Typparameter in der Auflistungsklasse nicht bearbeitet werden kann. Die Lösung besteht darin, den zweiten Typparameter zu eliminieren.

Kann nicht sagen, warum das funktioniert, nur dass es funktioniert. Hoffe, es hilft jemand anderem auf der Straße.

58

Sie müssen auch einen Standardkonstruktor für den Typ in der Auflistung haben.

+0

Danke! Das hatte ich vermisst. –

+4

Dies ist die Antwort, die überprüft werden sollte>. mpen

+0

Ja, das ist die Antwort für das gleiche Problem, das ich hatte. – Xenan

1

Fügen Sie Ihrer ItemsSource ein leeres Element hinzu, und entfernen Sie es anschließend. Möglicherweise müssen Sie CanUserAddRows danach wieder auf "true" setzen. Ich lese diese Lösung here: (Beiträge von Jarrey und Rick Roen)

Ich hatte dieses Problem, wenn ich die ItemsSource zu DataTable DefaultView setzte und die Ansicht leer war. Die Spalten wurden zwar definiert, sollten aber in der Lage sein, sie zu bekommen. Heh.

+0

Ugh. Vielen Dank. Das hat mich total verrückt gemacht. Ich gab schließlich die Entitäten auf und wechselte zu den getippten Datensätzen und sogar * das * scheiterte. Der Trick besteht darin, * zuerst die Sammlung zuzuordnen und dann * zu manipulieren, indem ein Objekt hinzugefügt und entfernt wird. – Brett

5

Meiner Meinung nach ist dies ein Fehler im DataGrid. Mike Blandford's link half mir endlich zu erkennen, was das Problem ist: Das DataGrid erkennt den Typ der Zeilen nicht, bis es eine reale Objekt gebunden hat. Die Bearbeitungszeile erscheint nicht b/c Das Datenraster kennt die Spaltentypen nicht. Sie würden denken, dass das Binden einer stark typisierten Sammlung funktionieren würde, aber nicht.

Um die Antwort von Mike Blandford zu erweitern, müssen Sie zuerst die leere Sammlung zuweisen und dann eine Zeile hinzufügen und entfernen.Zum Beispiel

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

Das hat den Trick für mich gemacht! – Dan

0

Für mich ist die beste Art und Weise bearbeitet werden asynchron zu implementieren DataGrid sieht wie folgt aus:

Ansicht Modell:

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> 

Dieses Muster erlaubt es, auf sehr einfache Weise mit dem Datenraster zu arbeiten, und auch der Code ist sehr einfach. Vergessen Sie nicht, den Standardkonstruktor für die Klasse zu erstellen, die Ihre Datenquelle darstellt.

Verwandte Themen