0

Im having a hard time with the following error: I have a listview that is binded to an observable collection. Lets say it looks like this:

XAMl:

 <ListView ItemsSource="{Binding myCollection}" SelectedItem="{Binding selectedItem}">

ViewModel:

 private Field selecteditem;
    public Field selectedItem { 
        get { return selecteditem; }
        set
        {
            selecteditem = value;    
        }
... //other code parts
myCollection = customClass.fillCollection(selectedLightColor, selectedDarkColor);

When i click on an item it is selected. When i click on another that is the selected one. This is totally okay. However at a certain point i need to recreate the whole observable collection that is connected to this listview. If i didnt select anything it recreates the collection perfectly. But, when i have a selected item it throws a System.NullReferenceException error to the property that is binded to the SelectedItem of the listview.
For the recreation im using the same code mentioned above (myCollection = customClass...) I cant find a solution that solves the problem. I have tried myCollection.Clear() and also selectedItem = null, but the error remained the same. Im glad to hear any help!

freasy
  • 11
  • 6

2 Answers2

0

I tried to reproduce the problem you describe, but it didn't work for me.
My example:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Core2022.SO.freasy
{
    public class Field
    {
        public int Number { get; } = random.Next();
        private static readonly Random random = new Random();

        public static IEnumerable<Field> GetRandomFields()
            => Enumerable.Range(0, random.Next(10, 20)).Select(_ => new Field()).ToList().AsReadOnly();
    }
}
using Simplified;
using System.Collections.Generic;

namespace Core2022.SO.freasy
{
    public class FieldsViewModel : BaseInpc
    {
        private IEnumerable<Field> _fields = Field.GetRandomFields();
        private RelayCommand? _refreshFields;

        public IEnumerable<Field> Fields { get => _fields; set => Set(ref _fields, value); }

        public RelayCommand RefreshFields => _refreshFields
            ??= new RelayCommand(_ => Fields = Field.GetRandomFields());

        private Field? _selectedField;
        public Field? SelectedField
        {
            get => _selectedField;
            set => Set(ref _selectedField, value);
        }
    }
}
<Window x:Class="Core2022.SO.freasy.FieldsWindow"
        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:Core2022.SO.freasy" xmlns:sys="clr-namespace:System;assembly=netstandard"
        mc:Ignorable="d"
        Title="FieldsWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:FieldsViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <sys:String x:Key="null">No Selected Field</sys:String>
    </Window.Resources>
    <UniformGrid Columns="2">
        <ListBox x:Name="listBox" ItemsSource="{Binding Fields}"
                 DisplayMemberPath="Number"
                 SelectedItem="{Binding SelectedField}"
                 VerticalAlignment="Center" HorizontalAlignment="Center"/>
        <UniformGrid Columns="1">
            <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">
                <TextBlock.Text>
                    <PriorityBinding>
                        <Binding Path="SelectedField.Number" Mode="OneWay"/>
                        <Binding Source="{StaticResource null}"/>
                    </PriorityBinding>
                </TextBlock.Text>
            </TextBlock>
            <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">
                <TextBlock.Text>
                    <PriorityBinding>
                        <Binding Path="SelectedItem.Number" Mode="OneWay" ElementName="listBox"/>
                        <Binding Source="{StaticResource null}"/>
                    </PriorityBinding>
                </TextBlock.Text>
            </TextBlock>
            <Button Content="Refresh Collection" Command="{Binding RefreshFields}"
                VerticalAlignment="Center" HorizontalAlignment="Center" Padding="15 5"/>
        </UniformGrid>
    </UniformGrid>
</Window>

Perhaps you missed an important detail of your implementation in the explanations, which is the cause of the error you described.
Try changing my simple example to reproduce your problem.

BaseInpc and RelayCommand classes.
Source Code Archive: freasy.7z

EldHasp
  • 6,079
  • 2
  • 9
  • 24
  • Hi! Thank you for trying to code an example, but i cant even make this work. My observable collection (myCollection in my example) gets recreated when i press a button. As i said it works perfectly when i never select an item. For some reason i have to unselect the selected item to avoid NullReferenceError when recreating the collection. I just cant figure out how i can do that. I have only seen code examples that dont follow the MVVM pattern and just change it in code-behind. – freasy Oct 18 '22 at 17:54
  • @freasy ,Hi! I cannot reproduce the problem you describe. And without that, I can't tell you how to fix it. I supplemented the answer with a link to the answer with the implementation of the base classes and the archive with the source codes. The code is fully debugged and working. – EldHasp Oct 18 '22 at 18:48
  • Sorry for replying late! Thank you again for taking a look at my problem, but I just couldnt make your code work. It gave me many error, including i dont use the correct C# version. I solved the problem (and will answer my own question now), I just forgot to reply, because i had been busy. – freasy Oct 22 '22 at 12:30
0

Because the property setter called a method which used my private variable (selecteditem) the program couldnt handle the selecteditem variable to be null!

I can finally recreate my collection by adding a statement to the setter:

private Field selecteditem;
public Field selectedItem { 
    get { return selecteditem; }
    set
    {
       selecteditem = value;
       if (selecteditem != null)
       {
           //call method and do stuffs
       }
            
    }
freasy
  • 11
  • 6