我正在尝试通过删除从数据库填充的另一个Datagrid中的项来填充DataGrid。 从原始版本中删除它们似乎完美无缺,但AllItems.Remove(allItem)似乎导致了问题。 每当我点击左侧网格上的“添加”时,右侧的网格就会填充一个。当我第二次尝试它时它没有做任何事情,第三次它崩溃了。
未处理的异常:System.InvalidOperationException:ItemsControl 与其项目来源不一致。查看内部异常 更多信息。 ---> System.Exception:开发人员的信息 (使用Text Visualizer读取此内容):抛出此异常是因为 用于控制'System.Windows.Controls.DataGrid的生成器 Items.Count:3',名称'AddedItemsGrid'已收到序列 CollectionChanged事件与当前状态不符 Items系列。检测到以下差异:
累计计数2与实际计数3不同。[累计 count是(最后重置时计数+ #Adds - 自上次重置后#Removes)。]
如果你不完全明白我在这里尝试的是一个简短的解释:
查看
<UserControl x:Class="VivesRental.GUI.View.NewRentalView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:VivesRental.GUI.View"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.15*" />
<RowDefinition Height="0.75*" />
<RowDefinition Height="0.1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="10px">
<Run FontWeight="Bold" FontSize="22" Foreground="Black" Text="New Rental for" />
<Run FontWeight="Bold" FontSize="22" Foreground="Black" Text="{Binding User.Name}" />
</TextBlock>
<Button Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Top" Content="Close" Command="{Binding CloseCommand}" Margin="3"></Button>
<DataGrid x:Name="AllItemsGrid" ItemsSource="{Binding AllItems}" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False" CanUserResizeRows="False" SelectionMode="Single" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="False" Grid.Row="1" Grid.Column="0">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Item.Name}"></DataGridTextColumn>
<DataGridTemplateColumn Width="0.2*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Add" Command="{Binding DataContext.AddItemCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding Id}" Click="OnAddButton" ></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid x:Name="AddedItemsGrid" ItemsSource="{Binding AddedItems}" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False" CanUserResizeRows="False" SelectionMode="Single" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="False" Grid.Row="1" Grid.Column="1">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Item.Name}"></DataGridTextColumn>
<DataGridTemplateColumn Width="0.2*">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<Button Content="Remove" Command="{Binding DataContext.RemoveItemCommand, RelativeSource={RelativeSource AncestorType=UserControl}}" CommandParameter="{Binding Id}"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="2" Grid.ColumnSpan="2" Content="Finish" Command="{Binding FinishCommand}" Margin="3"></Button>
</Grid>
</UserControl>
视图模型
public class NewRentalViewModel : ViewModelBase, IViewModel
{
private ItemService itemService;
private UserService userService;
private RentalItemService rentalItemService;
private ICollection<RentalItem> allItems;
private ICollection<RentalItem> addedItems;
private User user;
public RelayCommand CloseCommand { get; private set; }
public RelayCommand<int> AddItemCommand { get; private set; }
public RelayCommand<int> RemoveItemCommand { get; private set; }
public ICollection<RentalItem> AllItems
{
get { return allItems; }
set
{
allItems = value;
RaisePropertyChanged();
}
}
public ICollection<RentalItem> AddedItems
{
get { return addedItems; }
set
{
addedItems = value;
RaisePropertyChanged();
}
}
public User User
{
get { return user; }
set
{
user = value;
RaisePropertyChanged();
}
}
public NewRentalViewModel(int userId)
{
userService = new UserService();
itemService = new ItemService();
User = userService.Get(userId);
rentalItemService = new RentalItemService();
InstantiateCommands();
LoadItems();
}
private void InstantiateCommands()
{
CloseCommand = new RelayCommand(Close);
AddItemCommand = new RelayCommand<int>(AddItem);
RemoveItemCommand = new RelayCommand<int>(RemoveItem);
}
private void LoadItems()
{
AllItems = rentalItemService.GetAvailableRentalItems(new RentalItemIncludes(){Item = true});
AddedItems = new List<RentalItem>();
}
private void Close()
{
var viewModel = new NavigationViewModel();
var message = new NavigationMessage { ViewModel = viewModel };
Messenger.Default.Send(message);
}
private void AddItem(int itemId)
{
foreach (var allItem in AllItems)
{
if (allItem.Id == itemId)
{
AllItems.Remove(allItem);
AddedItems.Add(allItem);
break;
}
}
}
private void RemoveItem(int itemId)
{
}
}
View.cs
public partial class NewRentalView : UserControl
{
public NewRentalView()
{
InitializeComponent();
}
private void OnAddButton(object sender, RoutedEventArgs e)
{
//Item item = (Item)((Button)sender).Tag;
//AllItemsGrid.Items.RemoveAt(item.Id);
AllItemsGrid.Items.Refresh();
AddedItemsGrid.Items.Refresh();
}
}
答案 0 :(得分:0)
如果这是一个MCVE会有所帮助。例如,我需要假设您的ICollection<T>
是ObservableCollection
s。既然不是,那就意味着我不能重复你的问题而且必须猜测。
错误的指示是WPF正在努力跟上对可观察集合所做的更改。这通常不会发生。
在给定的AddItem relay命令中,它遍历AllItems集合。在迭代过程中,它从集合中移除一个项目,尽管它在紧接着之后突破了foreach。使用Linq的第一种方法可以避免这种方法:
private void AddItem(int itemId)
{
var allItem = AllItems.First(i=>i.Id == itemId);
AllItems.Remove(allItem);
AddedItems.Add(allItem);
}
但实际上你可以更进一步,让自己的生活更轻松。在XAML中,将CommandParameter="{Binding Id}"
更改为CommandParameter="{Binding}"
,并将AddItem的参数更改为RentalItem
而不是int
(也更改RelayCommand的声明)。这样,您就不需要找到该项目,因为它是作为参数传递的。
我希望这样做意味着可以及时处理对集合的更改。