ItemsControl несовместим с источником своих элементов - Gridbox - PullRequest
0 голосов
/ 12 мая 2018

Я пытаюсь заполнить DataGrid, удалив элементы из другого Datagrid, который был заполнен из базы данных. Удаление их из исходного, кажется, работает безупречно, но, похоже, AllItems.Remove (allItem) вызывает проблемы. Всякий раз, когда я нажимаю на Добавить в левой сетке, правая заполняется одним. Когда я пытаюсь сделать это второй раз, он ничего не делает, а в третий раз вылетает с этой строкой.

Необработанное исключение: System.InvalidOperationException: ItemsControl несовместимо с его источником предметов. Смотрите внутреннее исключение для Дополнительная информация. ---> System.Exception: информация для разработчиков (используйте Text Visualizer, чтобы прочитать это): Это исключение было вызвано, потому что генератор для управления 'System.Windows.Controls.DataGrid Items.Count: 3 'с именем' AddedItemsGrid 'получил последовательность События CollectionChanged, которые не согласуются с текущим состоянием Коллекция предметов. Были обнаружены следующие различия:
Накопленный счет 2 отличается от фактического счета 3. [Накопленный счет счетчик (Счет при последнем сбросе + # Adds - # удаления после последнего сброса).]

Если вы не совсем понимаете, что я пытаюсь сделать, вот краткое объяснение:

  • LeftGrid заполняется базой данных
  • Правая сетка заполняется нажатием кнопки добавления на левой сетке, в то время как элементы также удаляются из правой сетки
  • Нажатие на Finish отправляет коллекцию RightGrid в базу данных

My two Datagrids

View

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

ViewModel

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 голосов
/ 12 мая 2018

Было бы полезно, если бы это был MCVE . Например, я должен предположить, что ваши ICollection<T> с ObservableCollection с. Поскольку это не так, это означает, что я не могу повторить вашу проблему и должен будет угадать.

Указание на ошибку заключается в том, что WPF пытается не отставать от изменений, вносимых в наблюдаемую коллекцию. Обычно этого не происходит.

В данной команде ретрансляции AddItem она выполняет итерацию по коллекции AllItems. В середине итерации он удаляет элемент из коллекции, хотя сразу после него вырывается из foreach. Этого подхода можно избежать, используя метод Линка First:

 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). Таким образом, вам не нужно находить элемент, поскольку он передается в качестве параметра.

Я надеюсь, что это будет означать, что изменения в коллекции могут быть обработаны своевременно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...