2009-09-23 143 views
7

我正在创建一个带有DataGrid的WPF窗口,我想在网格的底部显示空白的“new item”行,允许我将新项目添加到网格中。出于某种原因,我的窗口上的网格上没有显示空白行。下面是我用来创建DataGrid标记:WPF DataGrid:空白行丢失

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

我想不通为什么空白行没有显示。我已经尝试了明显的东西(IsReadOnly="false",CanUserAddRows="True"),没有运气。任何想法为什么空白行被禁用?谢谢你的帮助。

回答

4

文森特·西巴尔张贴了article describing what is required for adding new rows to a DataGrid。有很多可能性,其中大部分取决于您使用的SelectedProject.Tasks的集合类型。

我会建议确保“任务”不是只读集合,并且它支持所需的接口之一(在前面的链接中提到),以允许使用DataGrid正确添加新项目。

+3

其实,任务是一个ObservableCollection 。我做了一个测试项目,将数据网格绑定到相同类型的集合,并且空白行出现在网格的底部。文森特的博客文章很好,但他让你听起来像你必须实现IEditableObject,但事实并非如此。绑定到ObservableCollection 的普通香草DataGrid应显示空白行。请参阅http://www.codeproject.com/KB/WPF/MVVM_DataGrid.aspx。 – 2009-09-23 18:36:10

+0

非常感谢你的帮助。真诚。 – Star 2013-07-06 13:29:37

5

终于回到了这个。我不打算改变公认的答案(绿色对勾),但这里是问题的原因:

我的视图模型封装领域类以提供WPF所需的基础设施。

VmCollection<VM, DM> 

其中DM是一个包裹域类,和DM是包装它WPF等级:I上wrap方法我使用,其包括具有两个类型的参数的集合的类写了CodeProject article

它truns的是,一些奇怪的原因,其在集合类第2类参数会导致WPF的DataGrid成为编辑。解决方法是消除第二个类型参数。

不能说为什么这个工作,只有它。希望它能帮助别人。

58

您还必须拥有集合中类型的默认构造函数。

+0

谢谢!我错过了。 – 2010-02-11 03:46:13

+4

这是应该检查的答案。<感谢随机用户! – mpen 2011-01-12 07:45:34

+0

是的,这是我遇到的同样问题的答案。 – Xenan 2011-04-24 20:07:07

1

添加一个空的项目到你的ItemsSource然后删除它。完成此操作后,您可能必须将CanUserAddRows重新设置为true。我读这个解决方案here:(由Jarrey和瑞克罗恩发布)

我有这个问题,当我将ItemsSource设置为DataTable的DefaultView和视图是空的。列被定义,但应该能够得到它们。嘿。

+0

呃。谢谢。这一直令我疯狂。我终于放弃了实体并转向输入数据集,甚至失败了*。诀窍是首先分配集合,然后通过添加和删除对象来操作它。 – Brett 2011-09-06 14:25:01

5

在我看来,这是DataGrid中的一个错误。 Mike Blandford's link帮助我最终意识到问题所在:DataGrid在识别出行的类型之后才能识别行,直到它具有绑定的实际对象。编辑行不出现b/c数据网格不知道列类型。你会认为绑定一个强类型的集合可以工作,但事实并非如此。

为了向迈克布兰福德的答复扩大,你必须先分配空的集合,然后添加和删除行。例如,

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

这为我做了诡计! – Dan 2014-07-30 16:40:35

0

对我来说,最好的方式来实现可编辑异步DataGrid看起来像这样:

视图模型:

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> 

该模式允许以非常简单的方式使用数据网格,代码也非常简单。 不要忘记为表示数据源的类创建默认构造函数。