Field changed to null???

capitolcapitol Member ✭✭

I was building a demo for another question on here when i came across another lovely problem with the Name field of a Model object in my List changing to null when you press a button to fire a command.

The first time you press either button, it works fine. But when you go back and select the other button, it changes the Name field to null.

The code below will explain it more:

ViewModel:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Windows.Input;
    using Xamarin.Forms;

    namespace BindingExample
    {
      public class MainViewModel : INotifyPropertyChanged
      {
        public event PropertyChangedEventHandler PropertyChanged;
        void OnPropertyChanged(string propertyName)
        {
          if (PropertyChanged != null)
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        private ObservableCollection<Model> _listOfModels { get; set; }
        public ObservableCollection<Model> ListOfModels
        {
          get { return _listOfModels; }
          set
          {
            if (_listOfModels != value)
            {
              _listOfModels = value;
            }
          }
        }

        private Model _selectedModel;
        public Model SelectedModel
        {
          get { return _selectedModel; }
          set
          {
            _selectedModel = value;
            OnPropertyChanged("SelectedModel");
          }
        }

        private bool _isPickerSelected = false;
        public bool IsPickerSelected
        {
          get { return _isPickerSelected; }
          set
          {
            _isPickerSelected = value;
            OnPropertyChanged("IsPickerSelected");
          }
        }

        private bool _isListSelected = false;
        public bool IsListSelected
        {
          get { return _isListSelected; }
          set
          {
            _isListSelected = value;
            OnPropertyChanged("IsListSelected");
          }
        }

        public ICommand OnPickerSelectedCommand { get; }
        public ICommand OnListSelectedCommand { get; }

        public MainViewModel()
        {
          OnPickerSelectedCommand = new Command(OnPickerSelectedCommandExecuted);
          OnListSelectedCommand = new Command(OnListSelectedCommandExecuted);

          ListOfModels = new ObservableCollection<Model>();

          ListOfModels.Add(new Model
          {
            Name = "Picker",
            Numbers = new List<Number>(){
              new Number {Name = "One", Value = 1 },
              new Number {Name = "Two", Value = 2 },
              new Number {Name = "Three", Value = 3 },},
            Enabled = true
          });
          ListOfModels.Add(new Model
          {
            Name = "List",
            Numbers = new List<Number>(){
              new Number {Name = "One", Value = 1 },
              new Number {Name = "Two", Value = 2 },
              new Number {Name = "Three", Value = 3 },},
            Enabled = false
          });
        }

        private void OnPickerSelectedCommandExecuted()
        {
          SelectedModel = ListOfModels.Where(e => e.Name == "Picker").First();
          IsPickerSelected = true;
          IsListSelected = false;
        }

        private void OnListSelectedCommandExecuted()
        {
          SelectedModel = ListOfModels.Where(e => e.Name == "List").First();
          IsPickerSelected = false;
          IsListSelected = true;
        }
      }

      public class Model
      {
        public string Name { get; set; }
        public List<Number> Numbers { get; set; }
        public bool Enabled { get; set; }
      }

      public class Number
      {
        public string Name { get; set; }
        public int Value { get; set; }
      }
    }

xaml:

    <?xml version="1.0" encoding="utf-8" ?>
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 x:Class="BindingExample.MainPage">
      <StackLayout>
        <StackLayout Orientation="Horizontal">
          <Label Text="Models:"/>
          <Button Text="Picker" Command="{Binding OnPickerSelectedCommand}"/>
          <Button Text="List" Command="{Binding OnListSelectedCommand}"/>
        </StackLayout>
        <StackLayout IsVisible="{Binding IsPickerSelected}" Orientation="Vertical">
          <Label Text="Select a Value:" />
          <Picker
            Title="picker_select"
            ItemsSource="{Binding Numbers}" BindingContext="{Binding SelectedModel}"
            ItemDisplayBinding="{Binding Name}"
            SelectedItem="{Binding Name}"/>
        </StackLayout>
        <StackLayout IsVisible="{Binding IsListSelected}" Orientation="Vertical">
          <Label Text="Select Options:"/>
          <ListView ItemsSource="{Binding Numbers}" BindingContext="{Binding SelectedModel}"
                    HasUnevenRows="True"
                    SeparatorColor="Gray"
                    VerticalOptions="FillAndExpand"
                    HorizontalOptions="FillAndExpand">
            <ListView.ItemTemplate>
              <DataTemplate>
                <ViewCell>
                  <StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">
                    <Label Text="{Binding Name}" TextColor="Black" FontSize="Small" 
                                 HorizontalOptions="StartAndExpand"/>
                    <Switch HorizontalOptions="End"/>
                  </StackLayout>
                </ViewCell>
              </DataTemplate>
            </ListView.ItemTemplate>
          </ListView>
        </StackLayout>
      </StackLayout>
    </ContentPage>

code behind:

    using Xamarin.Forms;

    namespace BindingExample
    {
      public partial class MainPage : ContentPage
      {
        public MainPage()
        {
          InitializeComponent();
          BindingContext = new MainViewModel();
        }
      }
    }


Best Answer

  • RHudsonRHudson CA ✭✭✭
    edited April 17 Accepted Answer

    @capitol

    You're getting a null exception because the Name property of the selected item is being set to null

    In your picker you are binding the SelectedItem to Name

    But when the picker goes invisible (when you click "List") there is no longer a selected item. Therefore null is being assigned to the Name property.

    So the next time you try to run your Linq query, it won't return a result.

    The whole thing looks rather convoluted.

    But perhaps trap the null on the property setter for Name like this:

    string _name;
    public string Name
         {
             get { return _name; }
    
             set { if(value != null)  _name = value;}
         }
    

Answers

  • ColeXColeX Member, Xamarin Team Xamurai

    It caused by the linq syntax , but i don't know why.

    After replacing

    SelectedModel = ListOfModels.Where(e => e.Name == "List").First();

    with

    foreach (var model in ListOfModels)
                {
                    if (model.Name == "List")
                    {
                        SelectedModel = model;
                        break;
                    }
                }
    

    The problem solved .

  • amirvenusamirvenus USMember ✭✭✭

    Always use FirstOrDefault instead of First

  • capitolcapitol Member ✭✭

    @amirvenus said:
    Always use FirstOrDefault instead of First

    No Bearing. I had initially used SingleOrDefault() with the same result :neutral:

  • RHudsonRHudson CAMember ✭✭✭
    edited April 17 Accepted Answer

    @capitol

    You're getting a null exception because the Name property of the selected item is being set to null

    In your picker you are binding the SelectedItem to Name

    But when the picker goes invisible (when you click "List") there is no longer a selected item. Therefore null is being assigned to the Name property.

    So the next time you try to run your Linq query, it won't return a result.

    The whole thing looks rather convoluted.

    But perhaps trap the null on the property setter for Name like this:

    string _name;
    public string Name
         {
             get { return _name; }
    
             set { if(value != null)  _name = value;}
         }
    
  • ColeXColeX Member, Xamarin Team Xamurai

    @capitol If problem have been solved , please accept the helpful comments as answer.

  • capitolcapitol Member ✭✭

    @RHudson said:
    @capitol

    You're getting a null exception because the Name property of the selected item is being set to null

    In your picker you are binding the SelectedItem to Name

    But when the picker goes invisible (when you click "List") there is no longer a selected item. Therefore null is being assigned to the Name property.

    So the next time you try to run your Linq query, it won't return a result.

    The whole thing looks rather convoluted.

    Big oversight on my part! Removed that selected Item as wasn't necessary for the demo and it works fine now.

    Thanks! :smile:

Sign In or Register to comment.