0

I'm very new to Xamarin and C#. So if What I am asking is rookie I apologize. But I have scoured the interwebz and Stack Overflow looking for why what I am doing isn't working and can't figure it out. As far as I can tell it should be working fine but maybe/hopefully I'm just missing something simple.

I'm using MVVM (mostly) and I have a ListView made up of objects called MobileBoardUser. That List View is set up like this

<ListView
        ItemsSource="{Binding BoardUsers}"
        HasUnevenRows="True"
        ItemSelected="StatusBoardPageListView_ItemSelected" >
        <ListView.ItemTemplate >
            <DataTemplate>
                <ViewCell>
                    //then the various StackLayout and Label objects etc.

In the code behind I am trying to use the ItemSelected method to pass the selected Item into a new page where all of it's properties will be displayed.

private void StatusBoardPageListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        if (e.SelectedItem == null)
        {
            return; 
        }
        MobileBoardUser userSelected = e.SelectedItem as MobileBoardUser;
        Navigation.PushAsync(new BoardUserPage(userSelected));
    }

The BoardUserPage Code Behind looks like this

using EIOBoardMobile.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text; 
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace EIOBoardMobile.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BoardUserPage : ContentPage
{
    public class UserProp
    {
        public string userprop { get; set; }
    }

    public class UserValue
    {
        public string uservalue { get; set; }
    }

    public ObservableCollection<UserProp> SelectedUserProps { get; set; } = new ObservableCollection<UserProp>();
    public ObservableCollection<UserValue> SelectedUserValues { get; set; } = new ObservableCollection<UserValue>();

    public BoardUserPage(MobileBoardUser selectedUser)
    {
        InitializeComponent();
        BindingContext = this;
        MobileBoardUser shownUser = selectedUser;

        foreach (var prop in shownUser.GetType().GetProperties())
        {
            if (prop.GetType() == typeof(String))
            {
                UserProp NewUserProp = new UserProp
                {
                    userprop = prop.Name.ToString()
                };
                SelectedUserProps.Add(NewUserProp);
            }
        }
        foreach (var prop in shownUser.GetType().GetProperties())
        {
            if (prop.GetType() == typeof(String))
            {
                UserValue NewUserValue = new UserValue
                {
                    uservalue = prop.GetValue(shownUser, null).ToString()
                };
                SelectedUserValues.Add(NewUserValue);
            }
        }
    }
  }
}

As you can see I have created two lists of objects, one to represent the property names and one to represent the actual values of those properties so they can be used in the xaml. In production these will be dynamic so it is important I be able to do it this way. To this end the BoardUserPage xaml looks like this

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:EIOBoardMobile.Views"
         x:Class="EIOBoardMobile.Views.BoardUserPage">
<ContentPage.Content>
    <StackLayout Padding="20">
        <ListView 
            ItemsSource="{Binding SelectedUserProps}"
            HasUnevenRows="True" >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Vertical" >
                            <Label Text="{Binding userprop}" HorizontalOptions="StartAndExpand" TextColor="Black" />
                                <ListView ItemsSource="{Binding SelectedUserValues}" HorizontalOptions="EndAndExpand" >
                                    <ListView.ItemTemplate>
                                        <DataTemplate>
                                            <ViewCell>
                                                <Label Text="{Binding uservalue}" HorizontalOptions="EndAndExpand" TextColor="Blue" />
                                            </ViewCell>
                                        </DataTemplate>
                                    </ListView.ItemTemplate>
                                </ListView>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage.Content>
</ContentPage> 

All of this compiles and I get no unhandled exceptions or run time errors. The code behind that passes the SelectedItem as MobileBoardUser into the new page works to navigate to BoarduserPage but when I get there the page is empty and doing nothing.

What have I done wrong?

Travis Fleenor
  • 167
  • 1
  • 11
  • On `Navigation.PushAsync(new BoardUserPage(userSelected));` what is the value of `userSelected.GetType()`? – mjwills Jun 09 '18 at 22:42
  • At the end of the `BoardUserPage(MobileBoardUser selectedUser)` constructor, what is the value of `SelectedUserProps.Length`? `SelectedUserValues.Length`? – mjwills Jun 09 '18 at 22:45
  • That's a good question. How can I find that out? I would expect it to be MobileBoardUser as that is what it is cast to. I guess the big question is when you cast e.SelectedItem back to the object type it was before does it keep all of it's original values and pass them in? I'm really hoping to avoid reconstructing the entire object. – Travis Fleenor Jun 09 '18 at 22:45
  • https://stackoverflow.com/questions/7528302/debugging-how-do-i-execute-code-line-by-line and https://stackoverflow.com/questions/794255/how-do-you-use-the-immediate-window-in-visual-studio – mjwills Jun 09 '18 at 22:46
  • Thanks. You kind of set me on the right track. the typeof(String) bit was returning no results. Also it looks like casting e.SelectedItem as MobileBoardUser DOES NOt pass in all the selected items property values. It just casts it into an empty object. – Travis Fleenor Jun 10 '18 at 00:48

1 Answers1

0

Ok after some trial and error I was actually able to figure this out. I had to make some changes to the code. The typeof statements were not constructed properly. For the SelectedUserProps I was getting the typeof the property rather the value. So I had to change that. Also the nested ListView inside another ListView was causing exceptions and failing to generate. Passing e.SelectedItem after casting actually DID work. It was the foreach comparison statements that were causing me grief. So the major changes I made were to the BoardUserPage code behind and the BoardUserPage xaml. Here are those changes. Primarily using one ObservableCollection instead of two (hence now only one foreach statement and correcting the type comparison so that I was comparing values rather than the properties themselves to typeof(String). Here is the code behind

using EIOBoardMobile.Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace EIOBoardMobile.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class BoardUserPage : ContentPage
    {
        public class UserProp
        {
            public string userprop { get; set; }
            public string uservalue { get; set; }
        }

        public ObservableCollection<UserProp> SelectedUserProps { get; set; } = new ObservableCollection<UserProp>();

        public BoardUserPage(MobileBoardUser selectedUser)
        {
            InitializeComponent();
            BindingContext = this;


            foreach (var prop in selectedUser.GetType().GetProperties())
            {

                if (prop.GetValue(selectedUser).GetType() == typeof(String))
                {
                    UserProp NewUserProp = new UserProp
                    {
                        userprop = prop.Name.ToString(),
                        uservalue = prop.GetValue(selectedUser).ToString()
                    };
                    SelectedUserProps.Add(NewUserProp);
                }
            }
        }
    }
}

and here is the View (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"
             xmlns:local="clr-namespace:EIOBoardMobile.Views"
             x:Class="EIOBoardMobile.Views.BoardUserPage">

        <StackLayout Padding="20" >
        <ListView 
                x:Name="Parent"
                ItemsSource="{Binding SelectedUserProps}"
                HasUnevenRows="True" >
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Orientation="Vertical" Padding="10" HeightRequest="100">
                                <Label Text="{Binding userprop}" HorizontalOptions="StartAndExpand" VerticalOptions="StartAndExpand" TextColor="Black" />
                                <Label Text="{Binding uservalue}" HorizontalOptions="EndAndExpand" VerticalOptions="EndAndExpand" TextColor="Blue" />
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
</ContentPage>

This displays the property names on the left and values on the right of only those properties which are strings. This was necessary to avoid displaying IDs and othe integer based key values from the database that would just be meaningless clutter to end users.

Travis Fleenor
  • 167
  • 1
  • 11