Home > Software engineering >  How to unselect a listview item when creating a new item collection? Im using observable collection
How to unselect a listview item when creating a new item collection? Im using observable collection

Time:10-22

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!

CodePudding user response:

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

CodePudding user response:

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
       }
            
    }
  • Related