Just want to save this somewhere

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">

  <android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >

    <LinearLayout
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:orientation="vertical">

      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="40dp"
          android:text="From" />

      <Mvx.MvxSpinner
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:textSize="40dp"
           local:MvxBind="ItemsSource FromLocations"
           local:MvxItemTemplate="@layout/mvxspinner_itemtemplate_location"
           local:MvxDropDownItemTemplate="@layout/mvxspinner_dropdownitemtemplate_location"
  ></Mvx.MvxSpinner>

      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="40dp"
          android:text="To" />

      <Mvx.MvxSpinner
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:textSize="40dp"
           local:MvxBind="ItemsSource ToLocations"
           local:MvxItemTemplate="@layout/mvxspinner_itemtemplate_location"
           local:MvxDropDownItemTemplate="@layout/mvxspinner_dropdownitemtemplate_location"
     ></Mvx.MvxSpinner>

      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="40dp"
          android:text="Helicopter" />

      <Mvx.MvxSpinner
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:textSize="40dp"
           local:MvxBind="ItemsSource Helicopters"
           local:MvxItemTemplate="@layout/mvxspinner_itemtemplate_location"
           local:MvxDropDownItemTemplate="@layout/mvxspinner_dropdownitemtemplate_location"
     ></Mvx.MvxSpinner>

      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="40dp"
          android:text="Price" />

      <TextView
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          android:textSize="40dp"
          android:text="RM 0.00" />

      <Button xmlns:a="http://schemas.android.com/tools"
          android:text="Book Now!"
          android:textSize="40dp"
          android:layout_width="fill_parent"
          android:layout_height="wrap_content"
          local:MvxBind="Click BookButton_Clicked"
          android:id="@+id/button1" />

      <!--<EditText
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:textSize="40dp"
      local:MvxBind="Text Hello" />
  
  <Button xmlns:a="http://schemas.android.com/tools"
      android:text="Meow"
      android:textSize="40dp"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      local:MvxBind="Click GoToChallengesClicked"
      android:id="@+id/button1" />
  
  <TextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:textSize="40dp"
      local:MvxBind="Text Hello" />-->

    </LinearLayout>
  </android.support.v4.widget.NestedScrollView>

  <android.support.design.widget.AppBarLayout
     android:id="@+id/appbar"
     android:layout_width="match_parent"
     android:layout_height="wrap_content">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        local:layout_scrollFlags="scroll|enterAlways">


      <Button
        android:layout_width="wrap_content"
        android:layout_height="?attr/actionBarSize"
        android:text="Departure"
        android:layout_gravity="right"
        />

      <ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
        android:layout_gravity="right"
    android:src="@android:drawable/ic_menu_save"
    style="?android:attr/borderlessButtonStyle"
    />

    </android.support.v7.widget.Toolbar>

  </android.support.design.widget.AppBarLayout>

  <android.support.design.widget.FloatingActionButton
       android:id="@+id/fab"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_gravity="end|bottom"
       android:layout_margin="16dp"
       android:src="@android:drawable/ic_menu_save" />

</android.support.design.widget.CoordinatorLayout>

 

FrameLayout

https://code.tutsplus.com/tutorials/android-user-interface-design-frame-layouts--mobile-4877

 

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ImageView
        android:id="@+id/ImageView01"
        android:layout_height="fill_parent"
        android:layout_width="fill_parent"
        android:src="@drawable/lake"
        android:scaleType="matrix"></ImageView>
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#000"
        android:textSize="40dp"
        android:text="@string/top_text" />
    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/bottom_text"
        android:layout_gravity="bottom"
        android:gravity="right"
        android:textColor="#fff"
        android:textSize="50dp" />
</FrameLayout>

In the above example, the z-index for ImageView will be 0 (bottom), the first TextView is 1 (middle) and the second TextView is 2 (top).

CoordinatorLayout - Tabbed View - MVVMCross

Now how do you make a Tabbed View with MVVMCross?

  1. Take advantage of the CoordinatorLayout.
  2. Add tabs from code behind as fragments.
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
  <android.support.design.widget.AppBarLayout
      android:id="@+id/appbar"
      android:layout_width="match_parent"
      android:layout_height="wrap_content">
    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        local:layout_scrollFlags="scroll|enterAlways" />
    <android.support.design.widget.TabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="16dp"
        local:tabGravity="center"
        local:tabMode="scrollable">
  
    </android.support.design.widget.TabLayout>
  </android.support.design.widget.AppBarLayout>
  <android.support.v4.view.ViewPager
      android:id="@+id/viewpager"
      android:layout_width="match_parent"
      android:layout_height="fill_parent"
      local:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
    [Activity(
           Label = "Cabar.Mobile.UI.Android"
           , Theme = "@style/MyTheme", ScreenOrientation = ScreenOrientation.Portrait)]
    //[Activity(Label = "Cabar.Mobile.UI.Android")]
    public class ChallengesTabbedView : MvxCachingFragmentCompatActivity<Core.ViewModels.ChallengesTabbedViewModel>
    {
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.ChallengesTabbedView);

            var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);
            SupportActionBar.SetDisplayHomeAsUpEnabled(true);
            SupportActionBar.Title = "SampleTabs";
            
            var viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);

            var fragments = new List<MvxCachingFragmentStatePagerAdapter.FragmentInfo>();
            fragments.Add(new MvxCachingFragmentStatePagerAdapter.FragmentInfo("Top", typeof(ChallengesTabbedTopView), ViewModel.ChallengesTabbedTopViewModel));
            fragments.Add(new MvxCachingFragmentStatePagerAdapter.FragmentInfo("My", typeof(ChallengesTabbedMyView), ViewModel.ChallengesTabbedMyViewModel));

            viewPager.Adapter = new MvxCachingFragmentStatePagerAdapter(this, SupportFragmentManager, fragments);

            ////If you want to start at specific tab
            ////viewPager.SetCurrentItem(ViewModel.CurrentPage, false);

            var tabLayout = FindViewById<TabLayout>(Resource.Id.tabs);
            tabLayout.SetupWithViewPager(viewPager);
        }

    }



CoordinatorLayout

Whenever you want awesome animation that follows the Material Design guideline, use CoordinatorLayout!

Reference: http://saulmm.github.io/mastering-coordinator

http://guides.codepath.com/android/handling-scrolls-with-coordinatorlayout

 http://www.android--tutorials.com/2016/07/android-coordinatorlayout-anchor-and.html

https://forums.xamarin.com/discussion/comment/192091

 

 

<?xml version="1.0" encoding="utf-8"?>

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/background_light"
    android:fitsSystemWindows="true"
    >

    <android.support.design.widget.AppBarLayout
        android:id="@+id/main.appbar"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true"
        >

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/main.collapsing"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp"
            >

            <ImageView
                android:id="@+id/main.backdrop"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                android:src="@drawable/material_flat"
                app:layout_collapseMode="parallax"
                />

            <android.support.v7.widget.Toolbar
                android:id="@+id/main.toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin"
                />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="20sp"
            android:lineSpacingExtra="8dp"
            android:text="@string/lorem"
            android:padding="@dimen/activity_horizontal_margin"
            />
    </android.support.v4.widget.NestedScrollView>

    <android.support.design.widget.FloatingActionButton
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_margin="@dimen/activity_horizontal_margin"
        android:src="@drawable/ic_comment_24dp"
        app:layout_anchor="@id/main.appbar"
        app:layout_anchorGravity="bottom|right|end"
        />
</android.support.design.widget.CoordinatorLayout>

...and the code behind to configure the Toolbar

 [Activity(Label = "View for FirstViewModel", Theme = "@style/MyTheme")]
    public class FirstView : MvxCachingFragmentCompatActivity<FirstViewModel>
    {
        
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView(Resource.Layout.FirstView);


            var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);
            SupportActionBar.SetDisplayHomeAsUpEnabled(false);
            SupportActionBar.Title = "SampleTabs";

        }
    }

This is the result from the XML

MvvmCross Inflaters Shortcut (Mvx.MvxRecyclerView, Mvx.MvxSpinner, etc)

If you ever think of why people are using Mvx.MvxSpinner but when you put it inside your MVVMCross app it doesn't work, then this is the reason.

http://stackoverflow.com/questions/39875747/classnotfoundexception-mvx-mvxlistview

 

Mvx.MvxListView mentioned in Alex's answer is a shortcut that is registered with the custom Inflater that does binding in MvvmCross. This means, if your Setup class does not tell where to look for Mvx, the shortcuts wont work.

In this case, I see you are using MvxAppCompatActivity, which comes from one of the Support packages. There is a separate Setup you inherit from there, which handles a lot of registration for you. It will also set up some tint aware views.

So in your Setup, you should inherit from MvxAppCompatSetup:

public class Setup : MvxAppCompatSetup
{
}

 

 

This should be enough to find Mvx.MvxListView. If it doesn't you can try adding more abbreviations by overriding ViewNamespaceAbbreviations in your Setup:

public class Setup : MvxAppCompatSetup
{
    ...

    protected override IDictionary<string, string> ViewNamespaceAbbreviations new Dictionary<string, string>
    {
        {"Mvx", "MvvmCross.Binding.Droid.Views"},
        {"MyViews", "My.Custom.Views"},
        // add more abbreviations here
    };
}
 

This will make MvvmCross look for views in MvvmCross.Binding.Droid.Views when you prefix them with Mvx in your axml files.

"Mvx" => "MvvmCross.Binding.Droid.Views" is a default one, and should work with any BindingInflater from both MvxAppCompatSetup, but also MvxAndroidSetup.

CQRS Pattern

So, I'm going to use the CQRS Pattern too. Miaw.

There are lots of explanations online, just google CQRS pattern. But to make the story short, here are the classes you need to have:

  public abstract class ZCommand
    {
        public abstract Result Execute(ApplicationDbContext db);
    }

 public abstract class ZEvent
    {
        public abstract Result Raise(ApplicationDbContext db);
    }

  public abstract class ZQuery<T>
    {
        public abstract T Execute(ApplicationDbContext db);
    }

  public abstract class QueryAsync<T>
    {
        public abstract Task<T> ExecuteAsync(ApplicationDbContext db);
    }

  public abstract class ZTask
    {
        public abstract System.Threading.Tasks.Task<Result> ExecuteAsync(ApplicationDbContext db);
    }

Then you'll have the Executor that executes the Command/Task/Events/Query. You can implement somewhere in your project where all your processes centralize. For example, in ASP.NET MVC you can put it in a BaseController and have all other controllers inherit it.

For example:

public class BaseController : Controller
    {
        private ApplicationDbContext db;

        public BaseController() : base()
        {
            this.db = new ApplicationDbContext(null);
        }
        
        public Result Execute(ZCommand zCommand)
        {
            return zCommand.Execute(db);
        }

        public async Task<Result> ExecuteAsync(ZTask zTask)
        {
            return await zTask.ExecuteAsync(db);
        }

        public Result Raise(ZEvent zEvent)
        {
            return zEvent.Raise(db);
        }

        public T Execute<T>(ZQuery<T> zQuery) where T : class
        {
            return zQuery.Execute(db);
        }

        protected async Task<T> ExecuteAsync<T>(QueryAsync<T> query) where T : class
        {
            return await query.ExecuteAsync(db);
        }
    }

Alright. How to use it? For example, if you want to make a Command where the User can add a Challenge into a database, you'll make a CreateChallengeCommand like so:

 public class CommandUserAddChallenge : ZCommand
    {

        private string applicationUserId;
        private Challenge challenge;

        public CommandUserAddChallenge(string applicationUserId, Challenge challenge)
        {
            this.applicationUserId = applicationUserId;
            this.challenge = challenge;
        }

        public override Result Execute(ApplicationDbContext db)
        {

            challenge.ApplicationUserId = this.applicationUserId;

            db.Challenges.Add(challenge);
            return db.Save();

        }
    }

And create an Action inside your Controller and execute the command, like so:

        public IActionResult Create(Challenge challenge)
        {
            var command = new CommandUserAddChallenge(this.currentUserId, challenge);
            var result = this.Execute(command);

            return RedirectToAction("edit", new { id = challenge.Id });

        }

How about query-ing? Same thing. First you implement the ZQuery<T>, like so:

public class QueryGetChallenges : ZQuery<IQueryable<Challenge>>
    {
        public override IQueryable<Challenge> Execute(ApplicationDbContext db)
        {
            return db.Challenges;
        }
    }

And then execute it in your Action, like so:

 public IActionResult Index()
        {

            var query = new QueryGetChallenges();
            IQueryable<Challenge> challenges = this.Execute(query);

            ViewBag.Challenges = challenges;

            return View();
        }

Great! Now you can look at the BM6 source code for a full but simple example of CQRS in action. 

Note: The class Result is a helper class I made that represents result of any executions. Here's the code:

public class Result
    {
        private ICollection<ResultCode> errors { get; set; }
        private ICollection<ResultCode> infos { get; set; }
        private ICollection<ResultCode> warnings { get; set; }

        public bool Succeeded
        {
            get
            {
                if (this.errors.Count > 0)
                {
                    return false;
                }
                return true;
            }
        }

        public IEnumerable<ResultCode> GetErrors()
        {
            return this.errors;
        }

        public IEnumerable<ResultCode> GetInfos()
        {
            return this.infos;
        }

        public IEnumerable<ResultCode> GetWarnings()
        {
            return this.warnings;
        }

        public void AddError(ResultCode error)
        {
            this.errors.Add(error);
        }

        public void AddInfo(ResultCode info)
        {
            this.infos.Add(info);
        }

        public void AddWarning(ResultCode warning)
        {
            this.warnings.Add(warning);
        }
    }

    public enum ResultCode
    {
        NA
    }

 

Xamarin Dev

Coincidentally, I'm starting to dev with Xamarin + MVVMCross. So, I'm a start by writing up stuffs about Xamarins and my dev. Mostly so that whenever I forget something, I have it all documented so I can just look it up again on this blog.

So what happened was I was trying out Xamarin.Forms, Xamarin.Native and Xamarin + MVVM Cross.

My impressions now after playing around with them for nearly 2 weeks:

- Xamarin.Forms gets you up really quick. I mean, you literally can publish in like 1 hour. However, the UI is just.... not enough if you want to do something that looks nice. They really mean it when they said Xamarin.Forms is only for business apps. But, I've seen some nice templates for Xamarin.Forms (specifically grialkit.com) so yeah.

- Xamarin.Native. Seems awesome and looks like actually the best compromise you can get without having to develop on Java/Swift.

- Xamarin + MVVM Cross: Seems like a good idea, because if I go through the normal Xamarin.Native route, I'm pretty sure I'd end up building something similar to MVVM Cross, so why not? However, currently I feel like I'm spending too much time connecting the viewmodels and stuff to the presentation and kinda 'fighting the Android / iOS framework' too much.. but nah.

For now I ultimately settle on MVVM Cross, though that may change later if I feel that I need to.

So blah blah blah. I'll just post the base codes I'd come up here. Currently I'm hosting on Visual Studio Cloud, but I may bring them to GitHub too.