Xamarin.Forms : Binding ข้อมูลด้วย MVVM pattern

“MVVM is the best way to architecture mobile apps”

Asfend Yar Hamid ซึ่งเป็น Microsoft MVP developer ท่านหนึ่งได้กล่าวไว้ เค้าคือใครน่ะเหรอ ผู้เขียนรู้จักเค้าผ่าน Udemy (คอร์สเรียนออนไลน์ที่เค้ากำลังฮอต ราคาถูก คุณภาพดี แอบรีวิว 555) ซึ่งวันนี้ผู้เขียนจะมาแนะนำการ Binding ข้อมูลของ Xamarin.Form app ด้วย MVVM pattern กันนะคะ

MVVM pattern คืออะไร

MVVM หรือ Model View ViewModel เป็น design pattern หรือรูปแบบในการวาง architecture ในการเขียน code นั่นเอง โดย

Model คือ ส่วนที่เก็บข้อมูลของ Application เรา ตัวอย่างเช่น Entity Class หรือไฟล์ POCO Class ของ object ต่างๆ ที่เกี่ยวข้องกับข้อมูลจะอยู่ที่ส่วนนี้


View คือ ส่วนที่ติดต่อกับ user ซึ่งเป็นส่วนไว้แสดงหน้า app ของเรานั่นเอง ซึ่งView จะไม่รู้อะไรเลยนอกจากการแสดงผล ส่วน Logic อื่นๆจะอยู่ใน ViewModel


ViewModel คือ ส่วนที่ทำหน้าที่เก็บข้อมูลทั้งหมดที่ View ต้องการ โดย View จะติดต่อ ViewModel ผ่าน Data-binding ซึ่งหาก View มีการเปลี่ยนแปลงก็จะส่งผลต่อ ViewModel ในทางกลับกันหาก ViewModel มีการเปลี่ยนแปลงก็จะส่งผลถึง View ด้วยเช่นกัน


ทำไมต้องใช้ MVVM กับ mobile app ?

MVVM ทำให้เราสามารถ separate หรือแยกส่วนการทำงานของ code ออกจากกันได้ชัดเจนตามหน้าที่ของมัน ซึ่งทำให้ง่ายต่อการจัดการ รองรับต่อการเปลี่ยนแปลง เหมาะสำหรับการพัฒนา Application ที่มีการเปลี่ยนแปลง UI บ่อยครั้ง เนื่องจากทุกการเปลี่ยนแปลงในส่วน view จะไม่กระทบต่อ ViewModel ที่เป็น business logic และยังมี Binder ซึ่งเป็นตัวช่วยจัดการการเปลี่ยนแปลงของข้อมูลใน View หรือใน ViewModel ทำให้ไม่จำเป็นต้องเขียน Code ในการควบคุม View เพื่อให้เปลี่ยนแปลงตาม

เริ่มกันเลยดีกว่า

เกริ่นไปเยอะแล้ว เรามาลองสร้าง app เพื่อ binding ข้อมูลในรูปแบบ MVVM ดูกันเลยค่ะ
Step 1 : สร้าง Xamarin.Forms project ขึ้นมาก่อน (วิธีสร้างและเลือก template สามารถอ่านได้จากบทความที่แล้ว => สร้าง Hello World app ง่ายๆด้วย Xamarin.Forms) ซึ่งจะได้ project structure ดังรูป

ทีนี้เราจะไม่ไปยุ่งในส่วน specific platform project (Android และ iOS) เราจะมาสร้าง MVVM ที่ share project กัน

Step 2 : สร้างโฟลเดอร์ Model, View และ View Model ขึ้นมา ดังรูป

Step 3: สร้าง class ชื่อ Employee.cs ลงในโฟลเดอร์ Model โดย code ข้างในมีดังนี้

using System;
using System.Collections.Generic;
using System.Text;

namespace MVVMBinding.Models
{
    public class Employee
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName
        {
            get { return string.Format("{0} {1}", FirstName, LastName); }
        }
    }
}

Step 4 : สร้าง ViewModel ชื่อ EmployeeVM ลงใน โฟลเดอร์ ViewModels โดยใน class นี้จะมีการ inherit และ implement interface ที่ชื่อ INotifyPropertyChanged ซึ่งเป็น interface ที่ช่วยให้ Binder property ทำงาน โดย code มีดังนี้

using MVVMBinding.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;

namespace MVVMBinding.ViewModels
{
    public class EmployeeVM : INotifyPropertyChanged
    {
        private ObservableCollection<Employee> _employees;
        public ObservableCollection<Employee> Employees {
            get
            {
                return this._employees;
            }
            set
            {
                this._employees = value;
                OnPropertyChanged();
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(
        [CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this,
            new PropertyChangedEventArgs(propertyName));
        }

        public EmployeeVM()
        {
            Employees = new ObservableCollection<Employee>();
        }

        public void AddNewEmployee(string fisrtName,string lastName)
        {
            Employee emp = new Employee()
            {
                FirstName = fisrtName,
                LastName = lastName
            };
            Employees.Add(emp);
        }
    }
}

Step 5 : สร้าง page ชื่อ EmployeePage ลงใน folder View โดยในส่วนของ EmployeePage .xaml ส่วนของ ListView จะมีการ Binding ข้อมูล กับ Employees ซึ่งเป็น property หนึ่งของ EmployeeVM สำหรับแสดงผลข้อมูล

<?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="MVVMBinding.Views.EmployeePage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="My Employee"
                VerticalOptions="CenterAndExpand" 
                HorizontalOptions="CenterAndExpand" />
            <StackLayout>
                <Label Text="ชื่อ"/>
                <Entry Placeholder="กรอกชื่อ" x:Name="fnameEntry"/>
                <Label Text="นามสกุล"/>
                <Entry Placeholder="กรอกนามสกุล" x:Name="lnameEntry"/>
                <Button x:Name="addBtn" Text="Add" Clicked="AddBtn_Clicked" />
                <ListView ItemsSource="{Binding Employees}" BackgroundColor="Beige">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
                                <Label Text="{Binding FullName}"/>
                            </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

และในส่วนของ code behind=> EmployeePage.xaml.cs ก็ให้เซตค่า BindingContext ไปยัง EmployeeVM ดัง code ต่อไปนี้

using MVVMBinding.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

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

namespace MVVMBinding.Views
{
	[XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class EmployeePage : ContentPage
	{
        private EmployeeVM vm;
        public EmployeePage ()
		{
			InitializeComponent ();
            vm = new EmployeeVM();
            this.BindingContext = vm;
		}

        private void AddBtn_Clicked(object sender, EventArgs e)
        {
            vm.AddNewEmployee(fnameEntry.Text, lnameEntry.Text);
            ClearEntry();
        }
        private void ClearEntry()
        {
            fnameEntry.Text = "";
            lnameEntry.Text = "";
        }
    }
}

Step 6 : เปิดไฟล์ App.xaml.cs ขึ้นมา และเซตค่า MainPage ให้เรียกไปยัง EmployeePage ดัง code ต่อไปนี้

using MVVMBinding.Views;
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace MVVMBinding
{
    public partial class App : Application
    {
        public App()
        {
            InitializeComponent();

            MainPage = new EmployeePage();
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

Step สุดท้าย : เสียบสาย Usb เชื่อมต่อระหว่างมือถือกับคอมของเรา build project แล้วก็กดรันโลดดด.. ผลลัพธ์ก็จะออกมาเช่นนี้

เป็นอันเสร็จสิ้นการสร้าง app Binding ข้อมูลแบบ MVVM pattern ด้วย Xamarin.Forms แล้วนะคะ ซึ่งผู้อ่านสามารถนำไปใช้เป็นแนวทางและประยุกต์ใช้ตามความเหมาะสมกับ app นั้นๆต่อไปค่า ^^
บทความถัดไป => Xamarin Essentials : Easy access Native Feature Platform