2014-01-13 160 views
6

我似乎遇到了通过接口本身将行添加到DataGrid的问题。 这里是UI截图:WPF DataGrid CanUserAddRows = True

Screenshot

正如你所看到的,0行被在数据库中找到因此没有在DataGrid右侧显示出来。 但是id像那里有一个空行,用于手动添加行。 DataGrid.CanUserAddRows设置为True,但不起作用。 这是DataGridxaml,我冒昧地删除了一些代码以使它更小。

PrivilegeDetailsView.xaml

<UserControl ... 
      d:DataContext="{d:DesignInstance impl:PrivilegeDetailsViewModel}"> 
    <DataGrid ... 
       ItemsSource="{Binding RolesHasPrivilegesOnObjects}" 
       AutoGenerateColumns="False" 
       CanUserAddRows="True"> 
     <DataGrid.Columns> 
      <DataGridTemplateColumn Header="Type" CanUserSort="True"> 
       <DataGridTemplateColumn.CellTemplate> 
        <DataTemplate DataType="{x:Type int:IRoleHasPrivilegeOnObjectListItemViewModel}"> 
         <Image Source="{Binding Icon}" ToolTip="{Binding ToolTip}"/> 
        </DataTemplate> 
       </DataGridTemplateColumn.CellTemplate> 
      </DataGridTemplateColumn> 
      <DataGridTextColumn Width="*" Header="Name" Binding="{Binding Name}"/> 
      <DataGridCheckBoxColumn Header="Select" Binding="{Binding HasSelect, UpdateSourceTrigger=PropertyChanged}"> 
       <DataGridCheckBoxColumn.ElementStyle> 
        <Style TargetType="CheckBox"> 
         <Style.Triggers> 
          <DataTrigger Binding="{Binding CanHaveSelect}" Value="True"> 
           <Setter Property="IsEnabled" Value="True"/> 
           <Setter Property="HorizontalAlignment" Value="Center"/> 
          </DataTrigger> 
          <DataTrigger Binding="{Binding CanHaveSelect}" Value="False"> 
           <Setter Property="IsEnabled" Value="False"/> 
           <Setter Property="HorizontalAlignment" Value="Center"/> 
          </DataTrigger> 
         </Style.Triggers> 
        </Style> 
       </DataGridCheckBoxColumn.ElementStyle> 
      </DataGridCheckBoxColumn> 
      ... 
     </DataGrid.Columns> 
    </DataGrid> 
</UserControl> 

PrivilegeDetailsView.xaml.cs

public partial class PrivilegeDetailsView : IPrivilegeDetailsView 
{ 
    public PrivilegeDetailsView() { InitializeComponent(); } 

    public DataGrid PrivilegesOnObjectsDataGrid { get { return PrivilegeDataGrid; } } 

    public IViewModel ViewModel 
    { 
     get { return (IViewModel)DataContext; } 
     set { DataContext = value; } 
    } 
} 

这里是ViewModel (VM)对于上述xamlView

镨ivilegeDetailsViewModel.cs

public class PrivilegeDetailsViewModel : ViewModelBase, IPrivilegeDetailsViewModel 
{ 
    private readonly IEventAggregator _eventAggregator; 
    private readonly IPrivilegeViewModel _privilegeViewModel; 
    private readonly IRoleHasPrivilegeOnObjectViewModelAdapterRepository _roleHasPrivilegeOnObjectViewModelAdapterRepository; 
    private ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel> _rolesHasPrivilegesOnObjects; 

    public PrivilegeDetailsViewModel(IPrivilegeDetailsView view, 
            IRoleHasPrivilegeOnObjectViewModelAdapterRepository roleHasPrivilegeOnObjectViewModelAdapterRepository, 
            IPrivilegeViewModel privilegeViewModel, 
            IEventAggregator eventAggregator) : base(view) 
    { 
     _roleHasPrivilegeOnObjectViewModelAdapterRepository = roleHasPrivilegeOnObjectViewModelAdapterRepository; 
     _privilegeViewModel = privilegeViewModel; 
     _eventAggregator = eventAggregator; 
     Initialize(); 
    } 

    protected override sealed void Initialize() 
    { 
     _privilegeViewModel.PropertyChanged += PrivilegeViewModelOnPropertyChanged; 
     _eventAggregator.GetEvent<ToggleSelectPrivilegeEvent>().Subscribe(ToggleSelectPrivilege); 
     ... 
    } 

    public new IPrivilegeDetailsView View 
    { 
     get { return (IPrivilegeDetailsView)base.View; } 
    } 

    public ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel> RolesHasPrivilegesOnObjects 
    { 
     get { return _rolesHasPrivilegesOnObjects; } 
     set 
     { 
      _rolesHasPrivilegesOnObjects = value; 
      OnPropertyChanged(); 
     } 
    } 

    public void Save() 
    { 
     if(RolesHasPrivilegesOnObjects == null) return; 
     _roleHasPrivilegeOnObjectViewModelAdapterRepository.SaveChanges(RolesHasPrivilegesOnObjects); 
    }   

    private void ToggleExecutePrivilege(object obj) 
    { 
     var toggle = !View.PrivilegesOnObjectsDataGrid.SelectedItems.Cast<IRoleHasPrivilegeOnObjectListItemViewModel>() 
          .All(x => x.HasExecute); 
     foreach(var selectedItem in View.PrivilegesOnObjectsDataGrid 
             .SelectedItems 
             .Cast<IRoleHasPrivilegeOnObjectListItemViewModel>() 
             .Where(selectedItem => selectedItem.Object 
                      .CanHavePrivilege("EXECUTE"))) { 
              selectedItem.HasExecute = toggle; 
             } 
    } 

    ... 

    private void PrivilegeViewModelOnPropertyChanged(object s, PropertyChangedEventArgs e) 
    { 
     switch(e.PropertyName) 
     { 
      //When the SelectedSchema changes in the parent VM, I get the new rows to be shown in the DataGrid. 
      case "SelectedSchema": 
       RolesHasPrivilegesOnObjects = _roleHasPrivilegeOnObjectViewModelAdapterRepository 
                .GetPrivilegesOnObjectsAssociatedWith((IRoleEntityViewModel)_privilegeViewModel.SelectedRole, 
                (IContainerEntityViewModel)_privilegeViewModel.SelectedSchema); 
       break; 
     } 
    } 
} 

这是DataGrid

RoleHasPrivilegeOnObjectEntityViewModel.cs

public class RoleHasPrivilegeOnObjectEntityViewModel : EntityViewModelBase<RoleHasPrivilegeOnObjectEntityViewModel, 
                 RoleHasPrivilegesOnObject>, 
                 IRoleHasPrivilegeOnObjectListItemViewModel 
{ 
    private readonly RoleHasPrivilegesOnObject _roleHasPrivilegesOnObject; 

    public RoleHasPrivilegeOnObjectEntityViewModel(RoleHasPrivilegesOnObject roleHasPrivilegesOnObject) 
    { 
     _roleHasPrivilegesOnObject = roleHasPrivilegesOnObject; 
     Role = new RoleEntityViewModel(_roleHasPrivilegesOnObject.Role); 
     Object = new ObjectEntityViewModel(_roleHasPrivilegesOnObject.Object); 
    } 

    public override EntityType EntityType { get { return EntityType.NONE; } } 

    public override RoleHasPrivilegesOnObject OriginalEntity { get { return _roleHasPrivilegesOnObject; } } 

    public IRoleEntityViewModel Role { get; set; } 

    public IObjectEntityViewModel Object { get; set; } 

    public string ToolTip { get { return _roleHasPrivilegesOnObject.ToolTip; } } 

    public bool HasExecute 
    { 
     get { return _roleHasPrivilegesOnObject.HasExecute; } 
     set 
     { 
      _roleHasPrivilegesOnObject.HasExecute = value; 
      OnPropertyChanged(); 
     } 
    } 

    public bool CanHaveExecute { get { return _roleHasPrivilegesOnObject.CanHaveExecute; } } 

    public override string Icon { get { return Object != null ? Object.Icon : string.Empty; } } 

    public override string NAME 
    { 
     get { return _roleHasPrivilegesOnObject.NAME; } 
     set 
     { 
      _roleHasPrivilegesOnObject.NAME = value; 
      OnPropertyChanged(); 
     } 
    } 

    ... 
} 

我知道这是一个很大的代码​​的每一行,我已经剥夺很多,并放置了几个点(...),以显示更多的代码存在。注意:我使用EF5PRISM

如何使DataGrid通过GUI接受新行?

回答

4

我最终做的部分/大部分是Maverik的建议。

我将ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel>更改为ObservableCollection<RoleHasPrivilegeOnObjectEntityViewModel>并创建了一个默认的构造函数,它以前没有。

然后问题是RoleHasPrivilegeOnObjectEntityViewModel需要设置一些字段和属性才能正常工作,所以我创建了一个公共Initialize函数来提供必要的参数。

我在DataGrid'sInitializingNewItem事件中添加了一个事件处理程序,其中我调用了Initialize函数。

private void PrivilegesOnObjectsDataGridOnInitializingNewItem(object s, InitializingNewItemEventArgs e) 
{ 
    var newItem = e.NewItem as RoleHasPrivilegeOnObjectEntityViewModel; 
    if (newItem == null) return; 
    var role = _privilegeViewModel.SelectedRole; 
    var schema = _privilegeViewModel.SelectedSchema;   
    newItem.Initialize(role.OriginalEntity, schema.OriginalEntity); 
} 

当试图ADDA新行,点击ComboBox没关火InitializeNewItemevent。但点击任何其他列解雇掉InitializeNewItemevent,并且因为在第一每个Row's​​有它自己的AvailableObjectTypes特性,ComboBoxItemSource如果ComboBox是任何其他列之前选择,从而使得空未设置。

那不是如此动人AvailableObjectTypesPrivilegeDetailsViewModel和改变ComboBox'sItemSource结合这一可接受的行为,帮助

ItemsSource="{Binding DataContext.AvailableObjectTypes, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" 
11

我相信你的问题是使用ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel>作为ItemsSource。为了DataGrid能够创建一个新行,必须有一个可以用空构造函数构造的类型。

如果您将其更改为ObservableCollection<RoleHasPrivilegeOnObjectEntityViewModel>,我相当确定您的行将开始添加。

+0

同时,也是类需要一个默认的构造(空)?或者,也许我可以为我自己的实现创建一个新的行,甚至可以听一些东西,因为每行的虚拟机在构建时都需要一些参数。 – furier

+0

在这种情况下,我想你可以使用'CellEditEnding'事件并手动添加一行 – Maverik