ساخت برنامه موبایل با Xamarin.Forms و MvvmCross

پرووید

دسته های مقالات

امروزه ساخت برنامه های cross-platform با استفاده از تکنولوژی های مختلف بسیار فراگیر شده
است. یکی از تکنولوژی هایی که امروزه برای ساخت چنین برنامه هایی استفاده می شود Xamarin.Forms است. بدون شک اطلاع دارید
که در حال حاضر بسته های آموزشی مختلفی بر روی وبسایت پرووید در رابطه با آموزش Xamarin.Forms قرار داده شده است که می
توانید به راحتی اقدام به خرید و استفاده از آنها کنید.

به دلیل ویژگی هایی که Xamarin.Forms در ذات خود دارد، استفاده از الگوی MVVM را در آن
بسیار ساده می کند. مباحث مربوط به Binding و Notification ها که پیش از این در برنامه های WPF وجود داشتند در
Xamarin.Forms قرار داده شده است. همین موضوع باعث می شود که بتوانیم به راحتی الگوی MVVM را در Xamarin.Forms پیاده سازی
کینم. یکی از ابزارهایی که برای پیاده سازی MVVM در Xamarin.Forms استفاده می شود فریم ورک MVVMCrosss است. قابل ذکر است
که در حال حاضر بسته ی آموزش ویدئویی معماری MVVM برای برنامه های موبایل Xamarin بر روی سایت پرووید قرار گرفته است که به
راحتی می توانید اقدام به خرید و استفاده از آن کنید.

دوستان امروزه ساخت برنامه های cross-platform با استفاده از تکنولوژی های مختلف بسیار
فراگیر شده است. یکی از تکنولوژی هایی که امروزه برای ساخت چنین برنامه هایی استفاده می شود Xamarin.Forms است. بدون شک
اطلاع دارید که در حال حاضر بسته های آموزشی مختلفی بر روی وبسایت پرووید در رابطه با آموزش Xamarin.Forms قرار داده شده
است که می توانید به راحتی اقدام به خرید و استفاده از آنها کنید.

زمانی که قصد ساخت برنامه ای را دارید که قرار است بر روی پلت فرم های مختلف اجرا شود چالش
های متعددی پیش روی شما قرار می گیرد. یکی از بزرگترین چالش ها هزینه است. ساخت یک برنامه برای پلتفرم های مختلف نیازمند
دانش در مورد هر کدام از آن پلتفرم ها و استفاده از تیم های برنامه نویسی با دانش کافی در هر کدام از آن پلتفرم ها الزامی
است.

با در نظر گرفتن چنین هزینه هایی، قدرت Xamarin.Forms دقیقاً آشکار می شود. با استفاده از
Xamarin.Forms شما می توانید یک برنامه را فقط یک بار بنویسید و بعد از آن می توانید آن برنامه را به راحتی در پلتفرم های
مختلف از قبیل اندروید، iOS و UWP اجرا کنید.

به دلیل ویژگی هایی که Xamarin.Forms در ذات خود دارد، استفاده از الگوی MVVM را در آن
بسیار ساده می کند. مباحث مربوط به Binding و Notification ها که پیش از این در برنامه های WPF وجود داشتند در
Xamarin.Forms قرار داده شده است. همین موضوع باعث می شود که بتوانیم به راحتی الگوی MVVM را در Xamarin.Forms پیاده سازی
کینم. یکی از ابزارهایی که برای پیاده سازی MVVM در Xamarin.Forms استفاده می شود فریم ورک MVVMCrosss است. قابل ذکر است
که در حال حاضر آموزش ساخت برنامه های Xamarin.Android و Xamarin.iOS با استفاده از MVVMCross به صورت کامل بر روی سایت
پرووید قرار گرفته است که به راحتی می توانید اقدام به خرید و استفاده از آن کنید.

و اما برنامه ای که در این آموزش خواهیم ساخت به منظور Load کردن تعدادی شی Contact در یک
لیست است که کاربر با انتخاب هر کدام از Contact ها می توانید جزییات مربوط به هر کدام را مشاهده کند. کار را با ساخت یک
برنامه ی ساده ی Xamarin.Forms آغاز می کنیم.

https://visualstudiomagazine.com/articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig1.asxh

در پنجره ی بعد باید پلت فرم هایی که قصد Support کردن آنها را دارید، Template پروژه و
استراتژی Code Sharing خود را انتخاب کنید. تقریباً تمامی گزینه ها را در حالت پیش فرض قرار می دهیم. برای Template برنامه
نیز گزینه ی Blank App را انتخاب کنید تا بتوانیم قسمت های مختلف برنامه از قبیل Navigation و View ها را خودمان ایجاد
کنیم. ضمناً، استراتژی Code Sharing را نیز به .NET Standard تنظیم می کنیم.

https://visualstudiomagazine.com/articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig2.asxh

ممکن است بدانید که در حال حاضر Xamarin.Forms به عنوان تکنولوژی رسمی مایکروسافت برای ساخت
برنامه های cross-platform استفاده می شود. با استفاده از Xamarin.Forms، کد مربوط به UI برنامه را با استفاده از XAML
پیاده سازی می کنیم و این UI به صورت Shared (اشتراکی) در بین پلت فرم های مختلف استفاده می شود. گزینه ی Code Sharing
Strategy که در ابتدای ساخت یک برنامه ی Xamarin.Forms نشان داده می شود مشخص می کند که فایل های اشتراکی (از قبیل فایل
های XAML) به چه روشی به اشتراک گذاشته شوند. در حال حاضر، دو روش Shared Project و .NET Standard Library برای ما در نظر
گرفته شده است.

پس از ساخت Solution، خواهید دید که چهار پروژه برای شما ساخته می شود. یکی از این چهار
پروژه حاوی کدهای اشتراکی شما می باشد و سه پروژه ی دیگر مربوط به پلت فرم هایی است که تصمیم به Support کردن آنها داشته
اید. برای مثال، در برنامه ی ما سه پروژه برای پلت فرم های Android، iOS و UWP در نظر گرفته شده است. علاوه بر این، فایل
های App.xaml و MainPage.xaml در پروژه ی اشتراکی ساخته می شوند. در همین مرحله باید بتوانید برنامه را Build و Run کنید.

شبیه دیگر پلتفرم هایی که از XAML استفاده می کنند، MVVMCross نیز از مفاهیم Data Binding و
Notification استفاده می کند. بنابراین، توصیه می شود که در استفاده از MVVMCross از الگوی MVVM استفاده کنید. ضمناً،
پیشنهاد می کنیم که بسته ی آموزشی پیاده سازی الگوی MVVM در WPF را حتما از وبسایت پرووید ببینید. پس دقت کنید که بجای
استفاده از Code-behind و قرار دادن کدهای برنامه در فایل هایی که پسوند cs دارند (مثل MainPage.xaml.cs) ما از ViewModel
استفاده خواهیم کرد.

علاوه بر این، ما از قرار دادن ViewModel ها در پروژه ای که در قسمت قبل ساختیم خودداری می
کنیم. به عبارت دیگر، ما ViewModel های برنامه را در یک پروژه ی دیگر از نوع Class Library قرار خواهیم داد.

https://visualstudiomagazine.com/articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig3.asxh

این موضوع نه تنها به Reusability کمک خواهد کرد، بلکه مفهوم Separation of Concerns را به
خوبی برای ما پیاده سازی خواهد کرد. این موضوع در تست کردن برنامه نیز مفید خواهد بود. دقت کنید که پس از ساخت این پروژه
باید یک رفرنس از آن را در چهار پروژه ی قسمت قبل اضافه کنیم.

https://visualstudiomagazine.com/articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig4.asxh

به منظور ساخت ViewModel های برنامه از قابلیت های MvvmCross استفاده می کنیم و از نوشتن
دستی ViewModel ها خودداری می کنیم.

قبل از اضافه کردن رفرنس به MvvmCross باید تمامی NuGet Package های برنامه را به اخرین
نسخه ی آنها به روز رسانی کنید. پس از آن پکیج MvvmCross.Forms را به تمامی پروژه ها به جز پروژه ی Class Library که در
قسمت قبل برای قرار دادن ViewModel ها ایجاد کردیم اضافه می کنیم. دقت کنید که از StarterPack استفاده نکنید چون در ورژن
ششم منسوخ شد.

https://visualstudiomagazine.com/articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig5.asxh

پس از این باید پکیج MvvmCross را به تمامی پروژه ها اضافه کنیم. قبل از شروع به استفاده از
MvvmCross باید تغییراتی را در برنامه ایجاد کنیم. ابتدا در پروژه ی Core فایل Class1 را به App تغییر نام دهید. علاوه بر
این کلاس App باید از MvxApplication ارث بری کند. تصویر زیر کلاس App را نشان می دهد.

 
public class App: MvxApplication
{
  public override void Initialize()
  {
    base.Initialize();

    RegisterAppStart();
  }
}

در حال حاضر وظیفه ی کلاس App تعریف نقطه ی شروع یا همان Entry Point برنامه می باشد. یکی
از تفاوت های مهم یک برنامه ی ساده ی Xamarin.Forms و برنامه ای که از MvvmCross استفاده می کند در این است که در برنامه
هایی که با فریم ورک MvvmCross نوشته می شوند Navigation از طریق View Model ها انجام می شود. این کار در ابتدای اجرای
برنامه بر اساس تعریف Entry Point برنامه انجام می شود. در حال حاضر نقطه ی شروع برنامه MainViewModel می باشد که با View
ای با نام MainPage مرتبط می شود. ضمنا این ارتباط بر اساس Convention ها انجام می شود. در تصویر زیر MainViewModel را
مشاهده می کنیم.

 
public class MainViewModel: MvxViewModel
{
 public string WelcomeText => "Hello Xamarin.Forms with MvvmCross";
}

در حال حاضر MainViewModel وجود ندارد. بنابر این فولدری با نام ViewModels اضافه می کنیم و
کلاس MainViewModel را به آن اضافه می کنیم. این کلاس باید از MvxViewModel ارث بری کند. تعریف این کلاس در ادامه آمده
است.

پس از انجام این تغییرات در پروژه ی Core کا را با پروژه ای که حاوی فایل های XAML می باشد
ادامه می دهیم. در حال حاضر دو فایل XAML در این پروژه قرار دارد: فایل App.xaml و MainPage.xaml. وظیفه ی App.xaml تعریف
Resource هایی است که در سرتاسر برنامه استفاده می شوند. برای مثال استایل ها و Template ها و حتی Brush ها. از آنجایی که
تمامی منطق اجرای برنامه توسط MvvmCross انجام می شود میتوانید تمامی کدهای درون Code Behind این فایل حذف کنید. درون این
فایل فقط نیاز به تابع سازنده و فراخوانی به متد InitializeComponent دارید. در قسمت زیر تصویری از فایل Code Behind را
میبینید.

 
public partial class App : Application
{
 public App ()
 {
 InitializeComponent();
 }
}

تغییراتی را نیز باید در فایل MainPage.xaml ایجاد کنیم. در ابتدای کار این فایل را به پوشه
ی جدیدی به نام Views منتقل می کنیم. علاوه بر این کلاس base این کلاس را باید از ContentPage به MvxContentPage تغییر
دهید. این تغییر را هم در فایل MainPage.xaml و هم در Code Behind آن یعنی MainPage.xaml.cs ایجاد کنید. تغییر دیگر این که
باید Label ی که در این فایل تعریف شده است را به پروپرتی WelcomeText بایند کنید. در قسمت زیر تصویری از فایل
MainPage.xaml را می بینید.

 


 
 
 
 


تا اینجای کار تغییرات مورد نیاز بر روی فایل های xaml تکمیل شده اند.

در ادامه باید تغییراتی را بر روی پروژه های هر کدارم از پلت فرم ها ایجاد کنیم. زمانی که
یک پروژه ی Xamarin.Forms در ویژال استادیو ایجاد می کنیم کدهایی به صورت پیش آماده برای ما ایجاد می شوند. زمانی که از
MvvmCross استفاده می کنیم بسیاری از این کدها مورد نیاز نمی باشند. تغییرات این قسمت را از پروژه ی مربوط به پلتفرم UWP
آغاز می کنیم.
فایل MainPage باید ا MvxFormsWindowPage ارث بری کند. علاوه بر این تمامی کدهای Code Behind را پاک کنید. فقط تابع سازنده
را به همراه فراخوانی که به InitilizeComponent زده شده است را نگه دارید. در قسمت پایین این کلاس را مشاهده می کنید.

 
public sealed partial class MainPage
{
 public MainPage()
 {
 InitializeComponent();
 }
}

در ادامه فایلی را با نام ProxyMvxApplication به پروژه اضافه کنید. از آنجایی که XAML در
UWP نمی تواند کلاس های جنریک را پشتیبانی کند این کلاس به عنوان یک پروکسی عمل می کند و کلاس جنریک را به صورت یک کلاس
غیرجنریک تعریف می کند. در ادامه کد مربوط به این کلاس را مشاهده می کنید.

 
public abstract class ProxyMvxApplication : 
MvxWindowsApplication<MvxFormsWindowsSetup<Core.App, XFwMvx.App>, Core.App, XFwMvx.App, MainPage>
{
}

علاوه بر این فایل App.xaml و App.xaml.cs را طوری تغییر می دهیم که از کلاس
ProxyApplication ارث بری کند. کدهای درون این کلاس را حذف کنید و فقط تابع سازنده و فراخوانی که به InitilizeComponent
زده شده است را نگه دارید. در قسمت پایین تصویر این کلاس را مشاهده می کنید.

 
sealed partial class App 
{
 public App()
 {
 this.InitializeComponent();
 }
}

علاوه بر این اگر در پروژه ی اندروید با خطای Error CS0234 روبرو شدید باید رفرنسی به
Mono.Android.Export به پروژه اضافه کنید. این موضوع در تصویر زیر نشان داده شده است.

https://visualstudiomagazine.com/Articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig6.asxh

تغییراتی که در پروژه ی اندروید باید ایجاد کنید بسیار ساده است. فایل MainActivity.cs را
به RootActivity.cs تغییر نام دهید. علاوه بر این تغییراتی که در تصویر زیر می بینید را در این فایل ایجاد کنید.

 
[Activity(Label = "XFwMvx", Icon = "@mipmap/icon", Theme = "@style/MainTheme",
MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class RootActivity : MvxFormsAppCompatActivity<MvxFormsAndroidSetup<Core.App, App>, Core.App, App>
{
}

آخرین تغییر در پروژه ی iOS انجام می شود. فایل مربوط به کلاس AppDelegate را شبیه تصویر
زیر تغییر دهید.

 
[Register("AppDelegate")]
public partial class AppDelegate
: MvxFormsApplicationDelegate<MvxFormsIosSetup<XFwMvx.Core.App, XFwMvx.App>, XFwMvx.Core.App, XFwMvx.App>
{
}}

در حال حاضر تمامی برنامه ها به درستی تنظیم شده اند. سعی کنید تمامی پروژه ها را تک تک
اجرا کنید. هر کدام از آنها باید عبارت Hello Xamarin.Forms with MvvmCross را در وسط صحفه به شما نشان دهند. تصویر زیر
خروجی برنامه را نشان می دهد.

https://visualstudiomagazine.com/Articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig7.asxh

حال که برنامه را راه اندازی کرده ایم و کدهای ابتدایی آن را ساخته ایم می توانیم شروع به
استفاده از قابلیت های Xamarin.Forms و MvvmCross کنیم و برنامه را پیش ببریم.
همانطور که پیش تر نیز گفتیم برنامه ی ما وظیفه ی نشان دادن اطلاعات مربوط به تعدادی مخاطب یا همان Contact را داریم. از
همین رو فولدر Services را در پروژه ی Core ساخته و اینترفیس IContactService و کلاس ContactService را به آن اضافه می
کنیم. این کلاس و اینترفیس وظیفه ی نمایش داده های مربوط به تعدادی Contact را دارند. در ضمن کلاس Service به عنوان Data
Model برنامه به فولدری تحت نام Models اضافه خواهد شد. در قسمت زیر کدهای مربوط به این دو کلاس و اینترفیس را مشاهده می
کنید.

 
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
}

public interface IContactService
{
IEnumerable FetchContacts();
}

public class ContactService : IContactService
{
public IEnumerable FetchContacts()
{
var contacts = new List();
for (int i = 0; i < 1000; i++)
{
contacts.Add(new Contact() {Id=i, Name = "contact= " + i});
}
return contacts;
}
}

حال باید فریم ورک MvvmCross را نسبت به این کلاس سرویس آگاه کنیم. علاوه بر این باید تتظیم
کنیم که در چه مکانی از کد از این سرویس استفاده شود. برای انجام این کار متد Initialize از کلاس App در پروژه ی Core را
شبیه کد زیر تغییر می دهیم.

 
public override void Initialize()
{
  base.Initialize();

  CreatableTypes()
    .EndingWith("Service")
    .AsInterfaces()
  .RegisterAsLazySingleton();

    RegisterAppStart();
}

با استفاده از این کد تمامی Type هایی که نام آنها با کلمه ی Service ختم می شود به عنوان
یک شی Singleton رجیستر شده و در تمامی برنامه مورد استفاده قرار می گیرد. در ادامه باید از این کلاس سرویس در
MainViewModel استفاده کنیم. به این منظور در تابع سازنده ی این کلاس یک شی از اینترفیس IContactService را به عنوان ورودی
دریافت می کنیم. MvvmCross به طور هوشمندانه متوجه می شود که تمامی وابستگی ها به این اینترفیس با یک شی از کلاس
ContactServic برطرف کند. در ادامه کد مربوط به این کلاس را مشاهده می کنید.

 

private IContactService ContactService { get; }
public MainViewModel(IContactService contactService)
{
 ContactService = contactService;
}

کلاس ContactService لیستی از Contact را می سازد که ما میتوانیم با استفاده از Data
Binding از درون MainViewModel از آن استفاده کنیم. برای این کار متد ViewAppeared را Override می کنیم. در ادامه کد مربوط
به این موضوع را مشاهده می کنید.

 
public ObservableCollection Contacts { get; }= new ObservableCollection();
public override void ViewAppeared()
{
base.ViewAppeared();

var contacts = ContactService.FetchContacts();
foreach (var contact in contacts)
{
Contacts.Add(contact);
}
}

یکی از موضوعاتی که قصد پیاده سازی آن را داریم این است که با کلیک کردن کاربر بر روی هر
کدام از Contact ها که درون لیستی بر روی صفحه ی اصلی برنامه نشان داده می شوند صفحه ی دیگری ظاهر شود و جزئیات مربوط به
آن Contact را نشان دهد. به همین منظور یک View Model دیگر به همراه View مربوط به آن را میسازسم و نام آن ها را به ترتیب
ContactDetailsViewModel و ContactDetailsView مز گذاریم. تصویر زیر کد مربوط به این ViewModel را نشان می دهد.

 
public class ContactDetailsViewModel : MvxViewModel
{
 public Contact Contact { get; private set; }
 public override void Prepare(Contact parameter)
 {
 Contact = parameter;
 }
}

همانطور که در تصویر مشاهده می کنید این کلاس از کلاس جنریک MvxViewModel ارث بری کرده است.
این کلاس متد abstract ی با نام Prepare را دارد که پارامتری از نوع کلاس Contact را دیافت می کند. این پارامتر در زمان
Navigation از MainViewModel به ContactDetailsViewModel به این کلاس پاس داده می شود. ضمنا عملیات Navigation با استفاده
از اینترفیس INavigationService ی اتفاق می افتد که به همراه MvvmCross در دسترس ما قرار گرفته است. یک پارامتر از نوع این
اینترفیس را به تابع سازنده ی کلاس MainViewModel اضافه خواهیم کرد. کد زیر این موضوع را نشان می دهد.

 

private IMvxNavigationService NavigationService { get; }
public MainViewModel(IMvxNavigationService navigationService, IContactService contactService)
{
 NavigationService = navigationService;
 ContactService = contactService;
}

آخرین موضوعی که باید انجام شود تعریف متدی است که امکان عملیات Navigation را فراهم کند.
متد ShowContactDetails را به همین منظور مطابق کد زیر اصافه خواهیم کرد.

 

public Task ShowContactDetails(Contact contact)
{
 return NavigationService.Navigate<ContactDetailsViewModel, Contact>(contact);
}

تغییرات نهایی اپدیت کردن کد XAML مربوط به MainPage می باشد تا بتواند لیستی از Contact ها
را نشان دهد. علاوه بر این فایل ContacContactDetail اضافه خواهیم کرد. کد زیر فایل MainPage را نشان می دهد.

 


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


رویداد ItemSelected مربوط به ListView که در این فایل تعریف شده است نیز باید شبیه کد زیر
هندل شود.

 

private void ContactSelected(object sender, Xamarin.Forms.SelectedItemChangedEventArgs e)
{
 ViewModel.ShowContactDetails(e.SelectedItem as Contact);
}

ضمنا یک Content Page با نام ContactDetailsPage به پروژه اضافه خواهیم کرد. تصویر زیر این
موضوع را نشان می دهد.

https://visualstudiomagazine.com/Articles/2018/05/08/~/media/ECG/visualstudiomagazine/Images/2018/05/0518vsm_Randolph_Fig8.asxh

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *