c # - En ItemsControl er inkonsekvent med sine elementer kilde - Gridbox

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøger at udfylde en DataGrid ved at slette elementer fra en anden Datagrid, der blev befolket fra databasen.
Fjernelse af dem fra den oprindelige ser ud til at virke fejlfrit, men AllItems.Remove (allItem) synes at skabe problemer.
Når jeg klikker på Tilføj i venstre ruten, bliver den rigtige befolket af en. Når jeg prøver det en anden gang, gør det ikke noget, og tredje gang det styrter sammen med denne linje.



  Uhåndteret undtagelse: System.InvalidOperationException: En ItemsControl
  er inkonsekvent med sine varer kilde. Se den indvendige undtagelse for
  mere information. ---> System.Exception: Information til udviklere
  (brug Text Visualizer til at læse dette): Denne undtagelse blev kastet fordi
  generatoren til styring 'System.Windows.Controls.DataGrid
  Items.Count: 3 'med navnet' AddedItemsGrid 'har modtaget sekvens af
  CollectionChanged events, der ikke er i overensstemmelse med den nuværende tilstand af
  Indsamling af varer. Følgende forskelle blev påvist:

  Akkumuleret tælling 2 er forskellig fra det faktiske antal 3. [[Akkumuleret
  tæller er (Tæller til sidst Nulstil + #Adds - #Removes siden sidste nulstilling).]]



Hvis du ikke forstår præcist hvad jeg forsøger her er en kort forklaring:



  • LeftGrid bliver befolket af database

  • RightGrid bliver befolket ved at klikke på add-knappen på LeftGrid, mens emnerne også fjernes fra RightGrid

  • Når du klikker på Afslut, sendes RightGrid-samlingen til databasen



Mine to datablade [11]


Udsigt


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

Bedste reference


Det ville hjælpe, hvis dette var en MCVE. For eksempel skal jeg antage, at dine ICollection<T> s er ObservableCollection s. Da det ikke er, betyder det, at jeg ikke kan gentage dit problem og skal gætte.


Indikationen fra fejlen er, at WPF kæmper for at holde øje med de ændringer, der foretages i den observerbare samling. Dette sker normalt ikke.


I den givne AddItem-relæ kommando, it iterates gennem AllItems kollektionen. I midten af ​​iterationen fjerner den et emne fra samlingen, om end det bryder ud af forgrunden straks efter. Denne fremgangsmåde kan undgås ved at bruge Linqs første metode:


 private void AddItem(int itemId)
 {
     var allItem = AllItems.First(i=>i.Id == itemId);
     AllItems.Remove(allItem);
     AddedItems.Add(allItem);
 }


Men du kan faktisk gå et skridt videre end det og gøre livet endnu nemmere for dig selv. I XAML ændrer du CommandParameter="{Binding Id}" til CommandParameter="{Binding}" og ændrer parameteren for AddItem til RentalItem snarere end en int (ændrer også erklæringen fra RelayCommand). På denne måde behøver du ikke at finde varen, fordi den bliver bestået som parameter.


Jeg håber at gøre dette vil betyde, at ændringerne i samlingen kan behandles rettidigt.