ItemsControl与其项目源不一致 - Gridbox

时间:2018-05-12 01:18:08

标签: c# wpf windows

我正在尝试通过删除从数据库填充的另一个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)。]

如果你不完全明白我在这里尝试的是一个简短的解释:

  • LeftGrid由数据库填充
  • 通过单击LeftGrid上的添加按钮来填充RightGrid,同时从RightGrid中删除项目
  • 单击Finish将RightGrid集合发送到数据库

My two Datagrids

查看

<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();
    }
}

1 个答案:

答案 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的声明)。这样,您就不需要找到该项目,因为它是作为参数传递的。

我希望这样做意味着可以及时处理对集合的更改。