Search code examples
c#xamlxamarin.formsmvvmdata-binding

Xamarin Forms Binding cannot be converted to type


New to Xamarin forms, have spent the past day and a half trying to figure out why some of my bindings work and others don't. They are constructed the same way but behave differently. Most of the elements are bound to observable collections of objects that I have created, pulled from ENUMS in my API. The XAML pickers load my collections correctly- when my app is running and I click on the picker I can view the list just fine. The problem is the binding of the SelectedItem. The Tag Type picker displays the selected item properly, the Simulation Type picker does not show my selected item- it is blank (The collection still displays when I click on the picker, just the selected item is blank). Both properties are set in the same way at the same time in my service that I created to implement the methods that interact with the properties in my model. The view model then creates an instance of that service to access the properties. One strange thing to note is that when hot reload is running and I remove then re-add this line: SelectedItem="{Binding MyItemSimulationType}" it works! But as soon as I close the program and re-run the application the selected item is blank again :/

The output window says the following:

[0:] Binding: '' cannot be converted to type 'TagType'
[0:] Binding: '' cannot be converted to type 'SimulationType'

The weird part is the binding for TagType works and SimulationType doesn't. Here is the XAML:

 <RefreshView x:DataType="local:ReadWriteViewModel" Command="{Binding LoadReadWriteValuesCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
    <ScrollView>
        <StackLayout Padding="10">

            <!--Item Properties-->
            <Frame>
                <StackLayout>
                    <Label Text="Item" FontSize="Subtitle" TextColor="Black" VerticalTextAlignment="Center" />

                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto" />
                            <RowDefinition Height="auto" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="auto"/>
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <!--Tag Type-->
                        <Label Grid.Row="0" Grid.Column="0" Text="Tag Type" VerticalTextAlignment="Center" HorizontalTextAlignment="End"/>
                        <Picker Grid.Row="0" Grid.Column="1" FontSize="Small" ItemsSource="{Binding MyItemHWTagTypes}" SelectedItem="{Binding MyItemHWTagType}" >
                            <Picker.Items></Picker.Items>
                        </Picker>

                        <!--Simulation Type-->
                        <Label Grid.Row="1" Grid.Column="0" Text="Simulation Type" VerticalTextAlignment="Center" HorizontalTextAlignment="End" />
                        <Picker Grid.Row="1" Grid.Column="1" FontSize="Small" ItemsSource="{Binding MyItemSimulationTypes}" SelectedItem="{Binding MyItemSimulationType}" HorizontalOptions="FillAndExpand">
                            <Picker.Items></Picker.Items>
                        </Picker>
                    </Grid>
                </StackLayout>
            </Frame>             
        </StackLayout>
    </ScrollView>
</RefreshView>

The view model:

    private ObservableCollection<TagType> _itemHWTagTypes;
    private TagType _itemHWTagType;
    private ObservableCollection<SimulationType> _itemSimulationTypes;
    private SimulationType _itemSimulationType;

    public ObservableCollection<TagType> MyItemHWTagTypes
    {
      get => _itemHWTagTypes;
      set => SetProperty(ref _itemHWTagTypes, value);
    }

    public TagType MyItemHWTagType
    {
      get => _itemHWTagType;
      set => SetProperty(ref _itemHWTagType, value);
    }

    public ObservableCollection<SimulationType> MyItemSimulationTypes
    {
      get => _itemSimulationTypes;
      set => SetProperty(ref _itemSimulationTypes, value);
    }

    public SimulationType MyItemSimulationType
    {
      get => _itemSimulationType;
      set => SetProperty(ref _itemSimulationType, value);
    }

   public Command LoadReadWriteValuesCommand { get; }

   public ReadWriteViewModel()
    {

      //Load Model
      LoadReadWriteValuesCommand = new Command(async () => await         ExecuteLoadReadWriteValuesCommand());
    }

async Task ExecuteLoadReadWriteValuesCommand()
    {
      IsBusy = true;

      try
      {
        var asc = await ASCService.GetASCObjectAsync();
    
          // ----- Set Item properties to default values in model
          MyItemHWTagTypes = asc.ModelItemHWTagTypes;
          MyItemHWTagType = asc.ModelItemHWTagType;
          MyItemSimulationTypes = asc.ModelItemSimulationTypes;
          MyItemSimulationType = asc.ModelItemSimulationType;
     }
      catch (TaskCanceledException tcex)
      {
        Debug.WriteLine(tcex);
      }
      finally
      {
        IsBusy = false;
      }
    }

If more code is needed please let me know, I tried to keep it simplified in my example code here and removed the extra code that doesn't relate to my problem. All of my properties in ExecuteLoadReadWriteValuesCommand() are being set correctly so I am sure that is not the problem. I am also getting lots of other spam in my output window, I don't think these messages relate but maybe? These are the ones that look potentially problematic:

[TabLayout] MODE_SCROLLABLE + GRAVITY_FILL is not supported, GRAVITY_START will be used instead
[Choreographer] Skipped 38 frames!  The application may be doing too much work on its main thread.
[OpenGLRenderer] Davey! duration=1656ms; Flags=0, IntendedVsync=1769860264400, Vsync=1770843597694, OldestInputEvent=9223372036854775807, NewestInputEvent=0, HandleInputStart=1770846662700, AnimationStart=1770846714100, PerformTraversalsStart=1770847196400, DrawStart=1771495643200, SyncQueued=1771503136700, SyncStart=1771503918600, IssueDrawCommandsStart=1771504436800, SwapBuffers=1771515968100, FrameCompleted=1771517457000, DequeueBufferDuration=303000, QueueBufferDuration=902000, 

Solution

  • I figured it out! You cannot set the binding property to the value in position [0] of the collection. I went through and set the default values to position [1] and it worked! Not sure if it's a bug or just how it works, but glad that's over.