WPF DataGrid CanUserAddRows = True
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21085275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF DataGrid CanUserAddRows = True
提问by furier
I seem to have a problem with adding rows to a DataGridthrough the interface itself.
Here is a screenshot of the UI:
我似乎在DataGrid通过界面本身向 a 添加行时遇到问题。这是用户界面的屏幕截图:


As you can see, 0 rows were found in the database so nothing shows up in the DataGridon the right side.
But id like there to be one empty row there, for manually adding rows.
The DataGrid.CanUserAddRowsis set to Truebut has no effect.
Here is the xamlfor the DataGrid, I have taken the liberty of removing some of the code to make it smaller.
如您所见,在数据库中找到了 0 行,因此DataGrid右侧没有显示任何内容。但是 id 喜欢那里有一个空行,用于手动添加行。该DataGrid.CanUserAddRows设置为True,但没有任何效果。这里是xaml对DataGrid的,我已经采取去除一些代码,使其更小的自由。
PrivilegeDetailsView.xaml
权限详细信息视图.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
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; }
}
}
Here is the ViewModel (VM)for the xamlViewabove:
下面是ViewModel (VM)对xamlView上面:
PrivilegeDetailsViewModel.cs
权限详细信息ViewModel.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;
}
}
}
This is the VMfor each row in the DataGrid
这是VM每行的DataGrid
RoleHasPrivilegeOnObjectEntityViewModel.cs
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();
}
}
...
}
I know this is a lot of code, I have stripped away a lot and put in place a few dots (...) to show that more code exist. NOTE: Im using EF5and PRISM
我知道这是很多代码,我已经剥离了很多并放置了几个点(...)以表明存在更多代码。注意:我使用EF5和PRISM
How can I make the DataGridaccept new rows through the GUI?
如何DataGrid通过 GUI 接受新行?
采纳答案by furier
What I ended up doing was partially/Mostly what Maverik suggested.
我最终做的部分/主要是 Maverik 的建议。
I changed ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel>to be ObservableCollection<RoleHasPrivilegeOnObjectEntityViewModel>and created a default constructor, which it didn't previously have.
我更改ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel>为ObservableCollection<RoleHasPrivilegeOnObjectEntityViewModel>并创建了一个默认构造函数,它以前没有。
The issue then was that the RoleHasPrivilegeOnObjectEntityViewModelneeds some fields and properties set in order to function, so I created a public Initializefunction to provided the necessary parameters.
然后的问题是RoleHasPrivilegeOnObjectEntityViewModel需要设置一些字段和属性才能运行,所以我创建了一个公共Initialize函数来提供必要的参数。
I added an event handler to the DataGrid'sInitializingNewItemevent, where i called the Initializefunction.
我向事件添加了一个事件处理程序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);
}
When trying to adda new row, clicking the ComboBoxdidn't fire off the InitializeNewItemevent. But clicking any other column fired off the InitializeNewItemevent, and since at first each Row'sVMhad it's own AvailableObjectTypesproperty, the ComboBoxItemSourcewas not set if the ComboBoxwas selected before any other column, thus making it empty.
尝试添加新行时,单击ComboBox没有触发InitializeNewItemevent. 但是单击任何其他列会触发InitializeNewItemevent,并且由于最初每个列Row'sVM都有自己的AvailableObjectTypes属性,因此ComboBoxItemSource如果ComboBox在任何其他列之前选择,则不会设置,从而使其为空。
That was not an acceptable behaviour so moving AvailableObjectTypesto the PrivilegeDetailsViewModeland changing the ComboBox'sItemSourcebinding to this helped
这是不是一个可以接受的行为让人感动AvailableObjectTypes的PrivilegeDetailsViewModel和不断变化的ComboBox'sItemSource,以这有助于绑定
ItemsSource="{Binding DataContext.AvailableObjectTypes, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
回答by Maverik
I believe your problem is using ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel>as ItemsSource. In order for DataGridto be able to create a new row, there has to be a type that can be constructed with an empty constructor.
我相信你的问题是使用ObservableCollection<IRoleHasPrivilegeOnObjectListItemViewModel>as ItemsSource。为了DataGrid能够创建新行,必须有一个可以用空构造函数构造的类型。
If you changed it to say ObservableCollection<RoleHasPrivilegeOnObjectEntityViewModel>instead, i'm pretty sure your rows will start getting added.
如果你改为说ObservableCollection<RoleHasPrivilegeOnObjectEntityViewModel>,我很确定你的行会开始被添加。

