0

I have a working UWP project using mvvmcross (4.0.0 beta8). In my core project I have a ServerBrowserViewModel

public class ServerBrowserViewModel : MvxViewModel
{
    #region Fields
    private IGameService gameService;
    #endregion

    #region Properties
    private IGameDiscoveryService _GameDiscoveryService;
    public IGameDiscoveryService GameDiscoveryService { get { return _GameDiscoveryService; } set { _GameDiscoveryService = value; RaisePropertyChanged(() => GameDiscoveryService); } }

    private GameHostDetail _SelectedHost;
    public GameHostDetail SelectedHost { get { return _SelectedHost; } set { _SelectedHost = value; RaisePropertyChanged(() => SelectedHost); } }

    //- TestData
    private ObservableCollection<GameHostDetail> _HostList;
    public ObservableCollection<GameHostDetail> HostList {
        get { return _HostList; }
        set {
            _HostList = value;
            RaisePropertyChanged (() => HostList);
        }
    }
    #endregion

    #region Constructors
    public ServerBrowserViewModel(IGameDiscoveryService gameDiscoveryService, IGameService gameService)
    { 
        GameDiscoveryService = gameDiscoveryService;
        GameDiscoveryService.StartListenBroadCastGameInfo();

        this.gameService = gameService;

        //- Initialize TestData
        HostList = new ObservableCollection<GameHostDetail>();
        HostList.Add (new GameHostDetail (){ GameName = "TestGame1", IP = "1.1.1.1", UserName = "TestUser1" });
        HostList.Add (new GameHostDetail (){ GameName = "TestGame2", IP = "1.1.1.2", UserName = "TestUser2" });
    }
    #endregion

The GameDiscoveryService has the following property

public class GameDiscoveryService : MvxNotifyPropertyChanged, IGameDiscoveryService
{
    private ObservableCollection<GameHostDetail> _HostList = new ObservableCollection<GameHostDetail>();
    public ObservableCollection<GameHostDetail> HostList { get { return _HostList; } set { _HostList = value; RaisePropertyChanged(() => HostList); } }

In my ServerBrowserView on the UWP side I have the following ListView

<ListView ItemsSource="{Binding GameDiscoveryService.HostList}" IsItemClickEnabled="True" >

            <ListView.ItemTemplate>
                <DataTemplate x:DataType="models:GameHostDetail">
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                        <TextBlock Text="{Binding UserName}"/>
                        <TextBlock Text=" - " />
                        <TextBlock Text="{Binding GameName}"/>
                        <TextBlock Text=" (" />
                        <TextBlock Text="{Binding IP}" />
                        <TextBlock Text=")" />
                    </StackPanel>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

Now this is all working flawlessly. When the ViewModel loads and there is a server running on the network, the view will display that server. Or when the refresh command is issued to the viewmodel, the list gets cleared and the active servers will resupply their details.

The problem I have is when I port this over to android.

So in my android view. I use an itemTemplate just like in UWP, here named itemtemplate_serverbrowser_hostdetail.axml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    local:MvxBind="Text UserName" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    android:text=" - " />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    local:MvxBind="Text GameName" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    android:text=" (" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    local:MvxBind="Text IP" />
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textSize="28dp"
    android:text=")" />

When I use the template in my Android view and set the itemsource to the HostList defined in the viewmodel, it works.

<Mvx.MvxListView
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="40dp"
    local:MvxBind="ItemsSource HostList"
    local:MvxItemTemplate="@layout/itemtemplate_serverbrowser_hostdetail" />

But When I try to use the same type of property on the Service used by the the viewmodel, my application crashes every single time.

local:MvxBind="ItemsSource GameDiscoveryService.HostList"

When I use this kind of mvxbind syntax, nothing shows up

local:MvxBind="{'ItemsSource':{'Path':'GameDiscoveryService.HostList'}}"

Can somebody tell me why this binding is not working in droid and if i will have to look out for the same issue in the ios port?

EDIT: If i add a property to the viewmodel that redirects to the service property, then the simple binding works just like it should. Still want to know why i cant directly bind to the property of a class inside the viewmodel.

// Rebind for android
    public ObservableCollection<GameHostDetail> HostList {
        get { return GameDiscoveryService.HostList; }
        set {
            GameDiscoveryService.HostList = value;
            RaisePropertyChanged (() => HostList);
        }
    }
Migaroez
  • 35
  • 6
  • 1
    You say the app crashes. What is the exception that is thrown? – Kiliman Jan 26 '16 at 21:15
  • Are you accessing/changing the ObservableCollection on a background thread? That could definitely cause crashes (ObservableCollection and INotifyCollectionChange is single threaded). – Stuart Jan 26 '16 at 22:03
  • Hi Stuart, thx for the reply and for mvvmcross. I ran into that problem earlier. I am in fact adding items to the collection from the background thread, but I push them to the main thread like so: Mvx.Resolve().RequestMainThreadAction(() => { HostList.Add(entry); }); – Migaroez Jan 27 '16 at 09:56

0 Answers0