اشتراک‌ها
Xamarin Live Player - VS 2017 version 15.4 & 15.5 فوق العاده

Last week Visual Studio 2017 version 15.4 and VS for Mac 7.2 were released into the stable channel. They include the very first release of the Xamarin Live Player capabilities in Visual Studios. This means you can simply update Visual Studio, turn on Xamarin Live Player (Preview), and get started visualizing your mobile apps with nothing more than VS and your iOS or Android device! 
Xamarin Live Player - VS 2017 version 15.4 & 15.5 فوق العاده
نظرات مطالب
توسعه برنامه های Cross Platform با Xamarin Forms & Bit Framework - قسمت پنجم
در صورتی که ویژوال استدیو موفق به نصب موارد مورد نیاز بر روی Mac نشود، می‌توانید در روی Mac خود Visual Studio for mac را نصب کنید که همه موارد مورد نیاز را نصب می‌کند.
در صورتی که فقط برای بیلد و دیباگ پروژه‌های iOS خود یک Mac مجازی را راه اندازی کرده اید و قصد استفاده از آن برای سایر امور را ندارید، بهتر است موقع انتخاب آیتم‌های قابل نصب، فقط iOS و NET Core. را انتخاب کنید و تیک Android و macOS و Workbooks and inspectors را بردارید که حجم کمتری دانلود و فضای کمتری استفاده شود.
نظرات مطالب
تقویم شمسی در Xamarin Forms
این کار هم مثل تمامی کارهای دیگه مون سورس باز هست. توی این پروژه از Rg Plugins Popup استفاده شده که فعلا محدود به Android/iOS/Windows هست، وگرنه خود کد ما می‌تونست روی هر پلتفرم ای که Xamarin Forms پشتیبانی می‌کنه (از جمله wpf) کار کنه.
مطالب
اجزاء معماری سیستم عامل اندروید (قسمت اول بررسی مجوزها و مفهوم Intent در اندروید) :: بخش هفتم
Intent چیست؟
معنای لغوی intent : هدف، قصد، نیت و امثالهم...
intent‌ها حامل انواع پیام‌هایی هستند که بواسطه آنها یک پیام خاص و یکتا، برای کنترل وظایف و یا انتقال داده‌ها یا درخواست جدیدی از سیستم به دیگری می‌فرستد و درخواست ما پذیرفته یا رد می‌شود.
intent‌ها به سه بخش مشخص شدۀ خاص تقسیم می‌شوند: فعالیت‌ها ( activity) ، خدمات یا سرویس‌ها (services) و broadcast receiver که به معنی اینست که اتفاقات را در سطح اندروید به صورت broadcast اعلام می‌کند و در سیستم پخش می‌شود؛ مانند زمانیکه سیستم عامل میخواهد بوت شود. در اینصورت این پیغام توسط یک مجوز خاص و با broadcast در سیستم عامل به کاربر اعلام می‌شود. broadcast receiver در اندروید و درون هسته گنجانده شده و فقط سیستم عامل قادر به اجرای آن است؛ تا در زمان یک اتفاق غیرمنتظره به برنامه یا کاربر اطلاع داده شود و تنها ما از طریق یک مجوز میتوانیم به آن دسترسی داشته باشیم.
اجازه دهید یک مثال ساده را انتخاب کنیم که در آن درخواست شما به مرورگر اندروید نیاز دارد تا بتواند محتویات یک URL را بارگیری و محتوایی را نمایش دهد. برخی از اجزای اصلی یک شئ شامل intent action و intent data خواهد بود. برای مثال ما می‌خواهیم که کاربر مرورگر خود را ببیند. به همین منظور ما از یک نوع intent استفاده می‌کنیم تا برای کار با برخی داده‌ها لازم باشد که از یک URL استفاده کند. به صورت زیر:
Intent.ACTION_VIEW
شئ intent به صورت زیر ساخته می‌شود:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(https://github.com);

برای فراخوانی باید کد زیر در برنامه درج شود:
startActivity(intent);

نکته: برای کنترل اینکه کدام برنامه‌ها می‌توانند intent خاصی را دریافت کنند باید یک مجوز (permission) را قبل از فراخوانی به آن ارسال کنیم.

بررسی مجوزها
پلتفرم اندروید سیستم دسترسی به اشیاء intent‌ها را از طریق استفاده از مجوزها کنترل می‌کند که بعضا بسیاری از توسعه دهندگان این مورد را به اشتباه درک می‌کنند و زمان فراخوانی، توجهی به اینکه مجوزها کجا باید ارسال شوند نخواهند داشت.
نگاهی می‌اندازیم به اینکه چگونه یک برنامه می‌تواند کاربرنهایی را با یک مجوز خاص درخواست کند؟ به چه صورت و از کجا؟ به چه میزان این درخواست معتبر است؟
یک مکانیزم اعتبارسنجی کنترل مجوز را در سیستم‌عامل اندروید بررسی و اداره خواهد کرد. هنگامیکه برنامه شما یک API را فراخوانی می‌کند، مکانیم اعتبارسنجی به سرعت وارد کار شده و بررسی خواهد کرد که آیا مجوزهای این درخواست معتبر هستند و اگر معتبر هستند تمامی مجوزهای لازم را دارند یا خیر؟ پس از یک پیش پردازش در کسری از ثانیه اگر درخواست و مجوزها کامل نباشد یک "SecurityException" ارسال خواهد شد.
فراخوانی‌های API در سه مرحله جداگانه انجام می‌شوند. اول، کتابخانه API بکار گرفته می‌شود. دوم، کتابخانه به صورت خصوصی برای خود یک رابط پروکسی که بخشی از همان کتابخانه API می‌باشد را ایجاد می‌کند و در آخر این رابط پروکسی به صورت خصوصی ارتباط و پردازش‌های مورد نظر برای پرس و جو را زمانیکه سرویس در حال اجرا می‌باشد، عملیاتی می‌کند تا فرآیند فراخوانی تکمیل گردد.
این فرآیند در تصویر زیر نمایش داده شده است:


استفاده از Self-Defined Permissions 

اندروید به توسعه دهندگان اجازه می‌دهد تا مجوزهای خود را ساخته و آنها را اجرا کنند. همانند مجوزهای سیستمی که پلتفرم آنها را بررسی می‌کند، شما باید خواص و برچسب‌های مورد نیاز را در فایل AndroidManifest.xml اعلام کنید. اگر برنامه‌ای می‌نویسید که یک نوعِ خاص از قابلیت دسترسی توسط توسعه دهندگان را فراهم می‌کند، شما می‌توانید برای حفاظت از توابع با مجوزهای سفارشی خود، مانع دسترسی‌های غیرمجاز شوید. به کدی که در فایل AndroidMainfest درج شده دقت نمایید:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.zenconsult.mobile.testapp" >
<permission android:name="net.zenconsult.mobile.testapp.permission.PURGE_DATABASE"
android:label="@string/label_purgeDatabase"
android:description="@string/description_purgeDatabase"
android:protectionLevel="dangerous" />
...
</manifest>
نام مجوز در کد فوق را باید در این قسمت تعیین کنید:
android:name <attribute>
خواص و ویژگی‌های مورد نیاز در این قسمت باید نوشته شوند (الزامیست)
android:label
android:description
تمامی موارد فوق به رشته‌هایی اشاره دارد که در فایل AndroidMainfest درج می‌شوند؛ لذا، ضرورت دارد تا دقت کافی به آنها داشته باشیم.
رشته‌هایی که در طی چند خط می‌نویسید وظیفه دارند تا مجوزهای لازم را شناسایی کرده و برای سیستم عامل توضیح دهند و اجازه می‌دهند تا فهرست مجوزها را بر روی دستگاه به کاربر نهایی نمایش دهد.
می خواهیم این رشته‌ها را به گونه‌ای دیگر تنظیم کنیم:
<string name=" label_purgeDatabase ">purge the application database </string>
<string name="permdesc_callPhone">Allows the application to purge the core database of
the information store. Malicious applications may be able to wipe your entire application
information store.</string>

مشخصه android:protectionLevel که در چند خط قبل در فایل تنظیمات درج شده است، مورد نیاز است و باید فراخوانده شود. همچنین می‌توانید یک مشخصه به نام android:permissionGroup را تعریف کنید تا خواص این مجوز را در برگیرد. اجازه بدهید تا مجوزهای سفارشی شما با مجوزهای سیستمی ارتباط برقرار کنند. لذا این ارتباط باعث بروز افزایش امنیت خواهد شد.
  برای مثال اضافه کردن مجوز purgeDatabase به صورت گروهی برای دسترسی به کارت sd صفاتی را به فایل AndroidMainfest تزریق می‌کند:
android:permissionGroup=" android.permission-group.STORAGE"
یکی از نکاتی که باید توجه داشته باشید این است که برنامه شما قبل از هر برنامه وابسته دیگری باید بر روی دستگاه نصب شود؛ چرا که اگر برنامه شما اول نصب نشود، به مشکل برخورد خواهید کرد و این مورد برای تمامی مجوزها صدق می‌کند.

مطالب
xamarin.android قسمت سوم
Theme
برای اینکه بتوانیم ظاهر گرافیکی layout‌ها را کنترل نماییم، از Theme که مجموعه‌ای از styleهای گرافیکی می‌باشد، استفاده می‌کنیم. در اندروید مجموعه‌ای از تم‌های از پیش ساخته شده که به آنها Builtin Theme نیز گفته می‌شود می‌توانیم استفاده کنیم. تم‌ها ظاهر گرافیکی کلیه کنترل‌های Layout را با نام‌های زیر، کنترل می‌کنند:
statusBarColor
textColorPrimary
colorAccent
ColorPrimary
WindowBackground

اگر ساختار زیر را در یک صفحه استاندارد برنامه‌های موبایل را در نظر بگیریم، styleها هر بخش، یک نام منحصر به فرد دارد:



اگر بخواهیم از style‌های از پیش طراحی شده‌ی اندروید استفاده نماییم، ابتدا میتوانیم در صفحه‌ی layout در زامارین، style مربوطه را از بخش Theme استفاده کرده و نتیجه را مشاهده کنیم. ولی تغییر style سبب تغییر layout در زمان اجرا نمی‌شود. هرگاه بخواهیم از styleهای استاندارد یا builtin اندروید استفاده نماییم، در Activity توسط خصوصیت Theme با فرمت:
[Activity(Theme = "@style/NameThem")]
تم را به‌عنوان تم داخلی وسپس نام کامل تم را می‌نویسیم.
 
CustomTheme
در طراحی فرم‌ها ممکن است بخواهیم از یک استایل خاص builtin استفاده کنیم؛ ولی ممکن است بعضی از استایل‌های آن را استفاده نکنیم، مانند تمی که از قبل استفاده شده‌است، از روش زیر استفاده می‌کنیم:
- بر روی دایرکتوری value راست کلیک میکنیم. گزینه add new item را انتخاب و یک فایل xmlfile را با نام style ایجاد میکنیم.
- style‌های جدید منابع application می‌باشند که در بخش resource از آن‌ها استفاده میکنیم. هر استایل جدید را توسط Style Tag مشخص میکنیم و در خصوصیت Name، نام Style را مشخص میکنیم.
ممکن است در یک Style نتوانیم و یا نخواهیم تمامی Style‌های مورد نیاز را تامین کنیم. از این رو توسط Parent، یک StyleBuition تعریف نموده که این Styleها از آن مشتق می‌شوند. اگر در Theme جدید گزینه‌ها مشخص شوند، تم اصلی تغییر نمی‌کند. در غیر اینصورت تمامی گزینه‌های تعریف شده در تم جدید از ThemParent مقدار دهی می‌شود.
توسط item می‌توان یک style را تعریف نمود. در Activity توسط
 [Activity(Theme = "@style/NameThem")]
می‌توانیم استایل سفارشی شده خودمان را مشخص کنیم.

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="MainTheme" parent="Theme.AppCompat.Light.DarkActionBar">
     <item name="windowNoTitle">true</item>
     <item name="windowActionBar">false</item>
  </style>
</resources>
 
  
Navigation Menu
کتابخانه متریال دیزاین کتابخانه جدیدی می‌باشد که به اندروید اضافه شده‌است. توسط  آن می‌توانیم کنترل‌های جدید را با استایل‌های جدید برای Appهای اندروید، تولید کنیم. ابتدا نیاز به نصب Component‌های ذیل در زامارین می‌باشد.
 
استفاده که از کتابخانه متریال دیزاین
برای اینکه بتوانیم Navigation menu را ایجاد کنیم، باید از نیوگت، کتابخانه‌های Appcompat و Designlibrary را انتخاب و نصب نماییم و اگر نگارش ویژوال استودیوی شما 15.7.3باشد، از ابتدا بصورت اتوماتیک نصب شده است و احتیاجی به این مراحل نمی‌باشد. بدیهی است در زمان نصب باید از نرم افزار‌های تحریم گذر نیز استفاده کرد.
  
ساخت Menu
NavigationMenu، منوی اصلی منو می‌باشد که با Swipping از گوشه راست به چپ، باز یا بسته می‌شود یا با کلیک بر روی دکمه‌ی Menu بر روی Toolbar، منو را باز یا بسته میکند.
قدم اول: نصب منو
منظور همان اضافه کردن کتابخانه‌ها است.
قدم دوم:
ابتدا باید گزینه‌های منو را در یک فایل xml تعریف نمود. هر گزینه‌ی آن از دو بخش متن اصلی منو و ID منو تشکیل شده‌است.
بر روی دایرکتوری Resource راست کلیک کرده و یک دایرکتوری یا پوشه را به نام Menu ایجاد می‌کنیم. بر روی دایرکتوری منو، راست کلیک کرده و یک فایل Xml را به آن اضافه می‌کنیم. برای آنکه بتوانیم در این فایل دستورات ساخت منو را نوشته و به نحوی که توسط اندروید قابل خواندن و تبدیل به منو باشد، ساختار منو را از آدرس زیر ویژوال استودیو دانلود میکنیم.
 <menu xmlns:android="http://schemas.android.com/apk/res/android">

توسط Group مجموعه گزینه‌های منو را را معرفی میکنیم.
هر گزینه در منو ی اصلی توسط یک آیتم مشخص میشود. برای آنکه هنگام کلیک بر روی هر گزینه از طریق برنامه نویسی بتوانیم گزینه انتخاب شده را شناسایی کنیم، یک آی دی منحصر بفرد را به هر گزینه اختصاص میدهیم. زمانیکه بر روی یک گزینه کلیک میشود، توسط این ID‌ها میتوانیم شناسایی کنیم کدام گزینه انتخاب شده‌است.
خصوصیت Android :Title متن اصلی منو را مشخص میکند.
 <?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <group android:checkableBehavior="single">
     <item android:id="@+id/menuItemHome" android:title="صفحه اصلی"></item>
     <item android:id="@+id/menuItemInsertProduct" android:title="ورود کالا جدید" ></item>
     <item android:id="@+id/menuItemListProduct" android:title="مشاهده کالاها"></item>
     <item android:id="@+id/menuItemExit"  android:title="خروج"></item>
  </group>
</menu>

سپس باید در Layout مورد نظر همانند صفحه Main، ساختار اصلی برنامه شامل Toolbar و Menu را بصورت زیر تعریف نماییم:
<android.support.v7.widget.Toolbar
  android:layout_width="match_parent"
  android:id="@+id/toolbar1"
  android:background="#33B86C"
  android:minHeight="?android:attr/actionBarSize"
  android:layout_height="wrap_content">
</android.support.v7.widget.Toolbar>

ساختار منو به صورت زیر است:
<?xml version="1.0" encoding="utf-8" ?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
  <group android:checkableBehavior="single">
    <item android:id="@+id/menuItemHome" android:title="صفحه اصلی"></item>
    <item android:id="@+id/menuItemInsertProduct" android:title="ورود کالا جدید" ></item>
    <item android:id="@+id/menuItemListProduct" android:title="مشاهده کالاها"></item>
    <item android:id="@+id/menuItemExit"  android:title="خروج"></item>
  </group>
</menu>
در Linearlayout ریشه، گزینه Fitssystemwindow را true میکنیم که سایز linearlayout را با سایز موبایل جدید اندازه می‌کند. سپس از toolbox، کنترل Toolbarرا به پنجره اضافه میکنیم که در بالای صفحه قرار می‌گیرد.
toolbar اضافه شده، toolbar استاندارد قبل از متریال دیزاین میباشد. در واقع toolbar اول، Toolbar استاندارد اندروید می‌باشد. برای آنکه از Toolbar متریال دیزاین استفاده کنیم، کنترل‌های متریال دیزاین در بخش supportlibrary اضافه میشود و Toolbar متریال دیزاین را اضافه میکنیم. علامت ؟ یعنی اینکه می‌خواهیم از اندازه سیستمی استفاده کنیم. اگر بخواهیم حداقل سایز Toolbarبر اساس پیش فرض در دستگاه‌های مختلف باشد، از علامت Android :attr ? استفاده میکنیم. اگر بخواهیم حداقل ارتفاع پیشنهادی اندروید در هر موبایل متصل شود، از خصوصیت Action Bar Size  استفاده میکنیم. این خصوصیت زمانی عمل میکند که Height  آن Wrapcontent باشد.
گذاشتن دکمه منو: برای آنکه بتوانیم دکمه منو را به Toolbar اضافه کنیم، از دکمه Image Button استفاده میکنیم که یک دکمه‌ی معمولی می‌باشد ولی خلاصه‌ی آن عکس است. در خصوصیت Back ground دکمه، بصورت زیر نام فایل آیکن منو را در دایرکتوری Drawable، مشخص میکنیم و خصوصیت src آن‌را null می‌کنیم تا تصویری بجز تصویر انتخابی نباشد.
برای آنکه بتوانیم پنجره اصلی منو را به صورتیکه دارای قابلیت حرکت به راست و چپ باشد، ایجاد کنیم، از کنترلی به‌نام  Drowerlayout استفاده میکنیم که بر روی صفحه قرار میگیرد. DrawerLayout در linearlayout ریشه قرار میگیرد و یا بعد از ToolBar و حتما باید خصوصیت fitsystemwindow کنترل Drawer را True کنیم. جهت نمایش گزینه‌های اصلی در Drawer از کنترل NavigationٰView استفاده می‌کنیم.
گزینه‌های منو در کنترلی به نام Navigationview قرار دارد. این کنترل باید در Drawerlayout قرار گیرد. توسط فضای نام منو، محل فایل xml را که منو درون آن قرار گرفته است، مشخص می‌کنیم. آدرس این دستور در این مسیر می‌باشد:
 xmlns:app="http://schemas.android.com/apk/res-auto"
Layout gravity  آن را end  قرار میدهیم که از سمت راست قرار بگیرد. Fit system Window را هم True میکنیم تا گزینه‌های داخل آن‌را هم Fit کند. Theme باید از نوع تم‌های متریال دیزاین و با کلمه Them . App Compact. ligth.NoActionBar باشد. برای آنکه اکتیویتی‌ها، متریال دیزاین را ساپورت کنند، میتوان از کلاس  App compact Activity  استفاده کنیم. Tool bar بصورت پیش فرض لیبل اکتیویتی را نشان می‌دهد و دستور زیر عنوان Toolbar را حذف میکند.
 SupportActionBar.SetDisplayShowTitleEnabled(false);
 
مدیریت گزینه‌های منو
به محض انتخاب یک گزینه درون NavigationView، رخدادی به نام NavigationItemSelected صادر می‌شود که توسط آن میتوانیم گزینه‌ی انتخاب شده را از طریق برنامه نویسی مدیریت کنیم. این کنترل در Android.Support.V7.Widget و NameSpace بالا قرار میگیرد. سپس یک رخ‌داد گردان را با نام navigationItemSelected پیاده سازی می‌کنیم. اطلاعات مربوط به گزینه‌ی انتخاب شده، در پارامتر دوم از این تابع NavigationView.NavigationItemSelectedEventArgs ذخیره می‌شود. ID، آیتم انتخاب شده در فایل Menu را باز می‌گرداند.
        var navigationview = this.FindViewById<NavigationView>(Resource.Id.navigationView1);
        navigationview.NavigationItemSelected += Navigationview_NavigationItemSelected;
        private void Navigationview_NavigationItemSelected(object sender, NavigationView.NavigationItemSelectedEventArgs e)
        {
            Intent intent = null;
            switch (e.MenuItem.ItemId)
            {
                case Resource.Id.menuItemHome:

                    break;
                case Resource.Id.menuItemExit:
                    Finish();
                    break;
                case Resource.Id.menuItemInsertProduct:

                    break;
                case Resource.Id.menuItemListProduct:

                    break;
            }
        }
 
مدیریت اکتیویتی‌ها توسط Menu
با انتخاب گزینه Menu باید اکتیویتی مربوطه انتخاب شود. بنابراین برای هر گزینه‌ی منو یک Layout و اکتیویتی را ایجاد می‌کنیم و اجرا میکنیم. ولی در اکتیویتی جدید Toolbar وجود ندارد.
 
تکنیک ادغام:
برای آنکه در Layoutهای مختلف، تولبار و منو و یا هر View دیگری را بصورت مشترک استفاده کنیم، یک فایل xml را به دایرکتوری Layout اضافه می‌کنیم. دستور Merge میتواند تمام layoutها را به درون layoutهای دیگر مانند home,insert ادغام و یا تزریق کند. جهت استفاده از Merge در layoutهای دیگر نیاز به Id منحصر به فرد می‌باشد.
<?xml version="1.0" encoding="utf-8" ?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbarlayout">
    <android.support.v7.widget.Toolbar android:layout_width="match_parent" android:id="@+id/toolbar1" android:background="#33B86C" android:minHeight="?android:attr/actionBarSize" android:layout_height="wrap_content">
        <ImageButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/imageButton1" android:background="@drawable/mainmenu" android:layout_gravity="end" />
    </android.support.v7.widget.Toolbar>
    <android.support.v4.widget.DrawerLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/drawerLayout1" android:fitsSystemWindows="true">
        <android.support.design.widget.NavigationView android:minWidth="25px" android:minHeight="25px" android:layout_width="200dp" android:layout_height="match_parent" android:layout_gravity="end" app:menu="@menu/menu" android:id="@+id/navigationView1" android:fitsSystemWindows="true" />
    </android.support.v4.widget.DrawerLayout>
</merge>

در اکتیویتی‌های دیگر باید Toolbar و مدیریت گزینه‌های منو با کد‌های مشابه Main انجام شود.
        private void Navigationview_NavigationItemSelected(object sender, NavigationView.NavigationItemSelectedEventArgs e)
        {
            Intent intent = null;
            switch (e.MenuItem.ItemId)
            {
                case Resource.Id.menuItemHome:
                    intent = new Intent(this, typeof(MainActivity));
                    break;
                case Resource.Id.menuItemExit:
                    Finish();
                    break;
                case Resource.Id.menuItemInsertProduct:
                    intent = new Intent(this, typeof(InsertActivity));
                    break;
                case Resource.Id.menuItemListProduct:
                    intent = new Intent(this, typeof(ListProductsActivity));
                    break;
            }
            if (intent != null) { }
        }
بنابراین دستورات xmlTollbar  و darawer layout در تمامی Layoutها و دستورات سی شارپ، کنترل کننده Toolbar و منو در تمامی اکتیویتی‌ها تکرار شده‌اند.
 
حل مشکلات Layout
یک فایل Xml را به Layout  اضافه می‌کنیم و درون آن Tag merge و کد‌های مشترک Drawer out و Toolbar را داخل تگ Merge اضافه می‌کنیم. جهت استفاده از کدهای (مقدار فایل ایکس ام ال ساخته شده که Tag merge داخل آن است)  Merge، در layout های دیگر، از دستور Include  استفاده می‌کنیم.
نام لی‌آوت را در خصوصیت Layout اضافه می‌کنیم. برای آنکه کد‌های سی شارپ کنترل کننده‌ی Toolbar و Menu چندین Toolbar وجود دارد که در یکی از آن‌ها یک کلاس واسط از کلاس app compat Activity  را به ارث میبریم. تابع Protected را از آن بازنویسی کرده و تمام کد‌های مدیریت Toolbar و منو را در آن پیاده سازی می‌کنیم. تمام اکتیویتی‌های برنامه را از این کلاس به ارث می‌بریم. بنابراین تابع InitieToolbar به تمامی فرزندان نیز به ارث برده می‌شود. در زمان اجرای دستورات، this ، اکتیویتی جاری می‌باشد.
    public class BaseAcitivity : AppCompatActivity
    {
        protected void InitieToolbar()
        {
            var toolbar = this.FindViewById<widgetV7.Toolbar>(Resource.Id.toolbar1);
            this.SetSupportActionBar(toolbar);
            //SupportActionBar.SetDisplayShowTitleEnabled(false);
            var imagebutton = toolbar.FindViewById<ImageButton>(Resource.Id.imageButton1);
            imagebutton.Click += Imagebutton_Click;
            var navigationview = this.FindViewById<NavigationView>(Resource.Id.navigationView1);
            navigationview.NavigationItemSelected += Navigationview_NavigationItemSelected;
        }

        private void Navigationview_NavigationItemSelected(object sender, NavigationView.NavigationItemSelectedEventArgs e)
        {
            Intent intent = null;
            switch (e.MenuItem.ItemId)
            {
                case Resource.Id.menuItemHome:
                    intent = new Intent(this, typeof(MainActivity));
                    break;
                case Resource.Id.menuItemExit:
                    Finish();
                    break;
                case Resource.Id.menuItemInsertProduct:
                    intent = new Intent(this, typeof(InsertActivity));
                    break;
                case Resource.Id.menuItemListProduct:
                    intent = new Intent(this, typeof(ListProductsActivity));
                    break;
            }
            if (intent != null)
                StartActivity(intent);
        }

        private void Imagebutton_Click(object sender, EventArgs e)
        {
            var drawerlayout = this.FindViewById<DrawerLayout>(Resource.Id.drawerLayout1);
            if (drawerlayout.IsDrawerOpen(Android.Support.V4.View.GravityCompat.End) == false)
            {
                drawerlayout.OpenDrawer(Android.Support.V4.View.GravityCompat.End);
            }
            else
            {
                drawerlayout.CloseDrawer(Android.Support.V4.View.GravityCompat.End);
            }
        }
    }
 
اگر بخواهیم یک تم در تمامی اکتیویتی‌ها  به صورت سراسری استفاده شود، از فایل تنظمیات اندروید بنام AndroidManifest در دایرکتوری Properties استفاده می‌کنیم و در  بخش Application Theme، نام تم را مشخص میکنیم:
 android:theme="@style/Theme.AppCompat.Light.NoActionBar"
 

ساخت TabPage
پیشنیاز: نصب کتابخانه‌های متریال دیزاین همانند قبل و طبق ورژن Sdk نصب شده
اگر بخواهیم چندین صفحه را بر روی یکدیگر Stack و یا Overload نماییم، از Tabpage استفاده می‌کنیم. صفحاتی‌که از TabPage استفاده می‌کنند، با انگشت جابجا میشوند و همانند برنامه‌ی واتساپ Fragment می‌باشند و هر Fragment دارای layout و اکتیویتی مربوط به خود می‌باشد. معماری layout آن بصورت زیر است:


ToolBar، در بالای فرم قرار می‌گیرد. TabLayou که بصورت TabPage آن‌ها را به عهده دارد. Viewpager مدیریت Layout‌ها را به هنگام Swipe یا جابجایی به عهده دارد.
یک layout را برای Toolbar قرار می‌دهیم. سپس Layout اصلی main را طراحی میکنیم. پس از اضافه کردن ToolBar، ابزار TabLayout را در بخش SupportLibrary متریال دیزاین انتخاب و در صفحه می‌کشیم. TabLayout در پایین Toolbar قرار می‌گیرد و با انتخاب رنگ یکسان برای هر دو، متصل و یکنواخت به نظر می‌رسد. سپس از Layout از Toolbar آیتم ViewPager را بر روی صفحه قرار می‌دهیم. اگر LayoutWeight آن را یک قرار دهیم، تمام ارتفاع صفحه را به ما تخصیص می‌دهد. زمانیکه در TabLayout تب‌ها جابجا می‌شوند یا بر روی یک آیکن کلیک می‌شود، صفحه مربوطه در بخش ViewPager به کاربر نمایش داده میشود. هر Page یک فرگمنت می‌باشد. به ازای هر فرگمنت یک Layout به دایرکتوری layout اضافه کرده و به ازای هر layoutFragment یک Activity Fragment را اضافه می‌کنیم. یک اکتیویتی از نوع را Android.Support.v4.AppFragment ایجاد میکنیم.
    public class Fragment1 : Android.Support.V4.App.Fragment
    {
        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
        }
        public override View OnCreateView(LayoutInflater inflater,
      ViewGroup container, Bundle savedInstanceState)
        {
            return inflater.Inflate(Resource.Layout.FragmentLayout1, container, false);
        }
    }
ابتدا باید viewpager در Layout اصلی را پیدا کرده و با دستور زیر به Tablayout متصل کنیم:
 var tablayout = FindViewById<Android.Support.Design.Widget.TabLayout>(Resource.Id.tabLayout1);
var viewpager = FindViewById<ViewPager>(Resource.Id.viewPager1);
tablayout.SetupWithViewPager(viewpager);
زمانیکه آیکن را در TabLayout انتخاب میکنیم یا با انگشت Swipe میکنیم، به ترتیب بین صفحات که از Position صفحه آغاز شده‌اند، حرکت می‌کنیم، باید فرگمنت همان Position را نشان دهیم و این مدیریت توسط بخشی به‌نام Adapter انجام میشود. یک Adapter را به کنترلر اضافه میکنیم و از کلاس Fragment pager adapter به ارث می‌بریم. بر روی کلاس Fragment pager adapter ، دکمه‌های کنترل و نقطه را میزنیم و سپس کلاس را پیاده سازی می‌کنیم. در این حالت دو تابع را به ما می‌دهد: تابع Get item .count مجددا بر روی کلاس پدر راست کلیک میکنیم. در تابع کانت تعداد کل صفحه‌ها را (Layout ها) را انتخاب میکنیم. هرگاه از یک صفحه به صفحه‌ی دیگری انتقال پیدا کنیم، موقعیت صفحه جدیدی که از یک شروع میشود را به تابع Get Item بر اساس موقعیت Object  از fragment مربوطه new کرده و بعنوان خروجی باز می‌گرداند.
    class TabFragmentAdapter : FragmentPagerAdapter
    {
        public TabFragmentAdapter(FragmentManager fm) : base(fm)
        {
        }
        public override int Count => 3;
        public override Fragment GetItem(int position)
        {
            switch (position)
            {
                case 0: return new Fragment1();
                case 1: return new Fragment2();
                case 2: return new Fragment3();
                default: return new Fragment1();
            }
        }


        //int f1() { return 100; }
        //int f1 => 100;
    }
و در اکتیویتی اصلی، کد زیر را برای Load فرگمنت‌ها نیز قرار می‌دهیم:
 viewpager.Adapter = new TabFragmentAdapter(this.SupportFragmentManager);
  
آیکن برای TabPage
سپس اگر بخواهیم آیکن‌های Tab را به ترتیب تعریف کنیم، از تابع Gettabat استفاده میکنیم. پارامتر ورودی آن موقعیت Tab page میباشد و Set icon هم آیکن‌های دایرکتوری Drawable را انتخاب میکند.
 tablayout.GetTabAt(0).SetIcon(Resource.Drawable.iconCall);
 

نمایش متن همراه با عکس
 اگر بخواهیم آیکن‌های تب پیج را سفارشی کنیم، از Layout استفاده میکنیم که عرض و ارتفاع آن wrap Content  باشند و درون آن یک Text view که معادل Lable میباشند، قرار میدهند:
 View iconlayout1 = LayoutInflater.Inflate(Resource.Layout.custom_TabIconLayout, null);
var txt = iconlayout1.FindViewById<TextView>(Resource.Id.tabTextIcon);
txt.Text = "تماس";
txt.SetCompoundDrawablesWithIntrinsicBounds(Resource.Drawable.iconCall, 0, 0, 0);
tablayout.GetTabAt(0).SetCustomView(iconlayout1);

کدهای مطلب جاری برای دریافت: Navigation-TabPage-samples.zip
مطالب
تقویم شمسی کاملا Native برای Blazor
یکی از مزایای Blazor، استفاده از دانش C# / HTML / CSS (که خیلی از ما اینها را هم اکنون بلد هستیم) برای نوشتن برنامه‌های وب (SPA / PWA)، برنامه‌های Android / iOS / Windows و وب‌سایت‌هایی با قابلیت Pre Rendering و SEO Friendly است. با یک بار کدنویسی به کمک Blazor، ولی با Configuration‌های متفاوت می‌توان خروجی‌های مختلفی را برای پلتفرم‌های مختلف گرفت؛ برای مثال Blazor Hybrid خروجی Android / iOS / Windows و Blazor Web Assembly خروجی PWA / SPA و در نهایت Blazor Static خروجی وب سایت می‌دهد. به علاوه حالت Blazor Server نیز وجود دارد که امروزه بزرگ‌ترین مزیت آن، Development experience فوق‌العاده‌اش هست که در آن با استفاده از Hot Reload، می‌توان تغییرات در فایل‌های SCSS / C# / Razor را به صورت آنی، بدون نیاز به Build مجدد، رفرش کردن و از دست دادن State مشاهده نمود. امکان استفاده از Nuget Packageهای DotNet ای در Android / iOS / Windows / Web در کنار امکان استفاده از امکانات Native هر پلتفرم نیز از دیگر مزایای این روش است.

اما یکی از موانع استفاده‌ی جدی از Blazor در پروژه‌های داخلی، نبود تقویم شمسی است که سبک بوده و پیش نیاز خاصی جز خود Blazor نداشته باشد. یک راه حل جدید برای حل این مشکل، استفاده از Bit Components است که اخیرا به صورت Open Source ارائه شده است. شما می‌توانید Repository مربوطه را Fork نموده، Clone نمایید، به فولدر src بروید و با ویژال استودیو، Bit.Client.Web.BlazorUI.sln را باز کنید و سورس کامپوننت‌ها را به همراه تست‌های خودکار آن ببینید.
در سایت مربوطه نیز می‌توانید دمویی از بیش از ۲۷ کامپوننت را شامل File uploader، Drop Down، Date Picker، Color Picker، Tree list و... مشاهده کنید که هر کدام دارای Documentation کامل بوده و آماده به استفاده در پروژه‌های شما هستند.
برای استفاده از Bit Components در پروژه خود، ابتدا Package مربوطه را نصب نمایید و سپس فایل js و css مربوطه را نیز به index.html یا Host.cshtml یا Layout.cshtml اضافه کنید (بسته به تنظیمات پروژه‌تان).
در Bit Components جز معدود مواردی که چند خطی با JavaScript توسعه داده شده‌است، کمپوننت‌ها با C# / Razor / CSS توسعه داده شده‌اند. این روش نسبت به روش‌هایی که بر روی کمپوننت‌های کاملا JavaScript ای، اصطلاحا Wrapper ایجاد می‌کنند، دارای دو مزیت سرعت بالاتر و تضمین کار کردن آن در حالت‌های مختلف مانند Pre Rendering است.
<link href="_content/Bit.Client.Web.BlazorUI/styles/bit.blazorui.min.css" rel="stylesheet" />
<script src="_content/Bit.Client.Web.BlazorUI/scripts/bit.blazorui.min.js"></script>  
همچنین در فایل Imports.razor نیز using زیر را اضافه کنید
@using Bit.Client.Web.BlazorUI
به همین سادگی! حال برای تست، از Bit Button به صورت زیر استفاده کنید و اگر درست بود، می‌توانید سراغ کامپوننت‌های پیچیده‌تر همچون Date Picker بروید.
<BitButton>Hello!</BitButton>
برای Bit Date Picker نیز در razor خود یک Property یا Field برای نگه‌داری Date انتخاب شده داشته باشید (برای مثال به اسم BirthDate) که لازم است از جنس DateTimeOffset باشد (دقت کنید، نمایش و گرفتن تاریخ به شمسی یا میلادی می‌تواند باشد که این بر اساس Culture جاری سیستم است (توضیحات اضافه‌تر در قسمت پایانی مقاله)، ولی در نهایت شما DateTimeOffset میلادی انتخاب شده را خواهید داشت)
<BitDatePicker SelectedDate="@BirthDate"></BitDatePicker>
این کامپوننت دارای تنظیمات بسیاری است که می‌توانید در این صفحه آنها را مطالعه و در پروژه خود تست نمایید. اما بد نیست در مورد قسمت Culture Info که کمی پیچیده‌تر است، توضیحاتی داشته باشیم.
در C# .NET، کلاس CultureInfo، وظیفه نگهداری مواردی چون چند زبانگی، تقویم‌های مختلف (اعم از شمسی و...)، موارد مربوط به ارز (برای مثال علامت $ یا ریال و...) را به عهده دارد. از جمله مزایای BitDatePicker، سازگاری با CultureInfo است، به نحوی که CultureInfo.CurrentUICulture هر چه که باشد، بر اساس آن عمل می‌کند. بنابراین می‌توانید در Program.cs پروژه Blazor خود بنویسید:
CultureInfo.CurrentUICulture = new CultureInfo("fa-IR");
و وقتی BitDatePicker در یکی از صفحات باشد، چون fa-IR از Persian Calendar استفاده می‌کند، پس تقویم به صورت شمسی نمایش داده می‌شود.

سوال اول: اگر بخواهیم در کل سیستم، تقویم شمسی باشد، ولی در یکی از صفحات میلادی چه؟ خب می‌توانیم در آن صفحه، به شکل زیر از BitDatePicker استفاده کنیم:
<BitDatePicker Culture="@(new System.Globalization.CultureInfo("en-US"))" />

سوال دوم: تقویم شمسی نمایش داده شده، اسامی ماه‌ها را به صورت فینگلیش نمایش می‌دهد و یا اسامی خلاصه شده روزها صحیح نیست!
این به خود BitDatePicker ربطی ندارد، بلکه به CultureInfo فارسی خود dotnet مرتبط است، اما شما چگونه می‌توانید این مورد را بهبود بدید؟
شما می‌توانید ابتدا با
var cultureInfo = CultureInfo.CreateSpecificCulture("fa-IR")
یک CultureInfo فارسی قابل ویرایش بسازید، برای مثال بنویسید
cultureInfo.DateTimeFormat.MonthNames = new[] { "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", "" };  
یک نمونه پیاده‌سازی کامل در اینجا
در ادامه لازم هست چه Culture Info ای را که خودتان سفارشی سازی کرده‌اید، یا Culture Info‌های سیستمی را در CultureInfo.CurrentUICulture قرار بدهید تا BitDatePicker از آن پیروی کند.
در صورت بروز هر گونه مشکلی یا درخواست اضافه شدن امکانی، در repo مربوطه روی GitHub می‌توانید یک issue را ثبت کنید.
نظرات مطالب
تگ گذاری در کامنت‌ها
نکته: با توجه به ارائه rider  و  android studio از طرف jetbrains و اینکه هر دو از  خانواده IntelliJIdea هستند. هر دو IDE مشابه یک دیگر هستند و امکان استفاده از ToDo تفاوتی با اندروید استودیو نمیکند.
نظرات مطالب
معرفی Xamarin و مزیت‌های استفاده از آن
این که عرض کردم حجم 3 الی 4 مگابایتی از نظر کاربران زیاد قابل قبول نیست به دلیل آماری است که از دوستان و آشنایانی که نرم افزار را برایشان جهت تست ارسال می‌نمودم بدستم رسیده است(در نسخه‌های بعدی با اندروید استودیو حجم کاهش زیادی پیدا نمود و یک سری باگ عجیب و غریب که منشا آنها را هنوز هم نمیدانم رفع شدند). که صد البته جامعه آماری بزرگی نیست و نتیجه آنرا براحتی نمی‌توان به کل جامعه تعمیم داد. بنده چندین app در مارکتهای داخلی منتشر نمودم که همگی زیر 2.3 مگابایت حجم دارند و اتفاقا بیشتر هم Game هستند و با گرافیک خوب. برای مثال اگر سودوکو 2 را در بازار(امیدوارم تصور نشود که قصد تبلیغ دارم) مشاهده نمایید میبینید که نرم افزار با این کیفیت و با این حجم نمی‌تواند خروجی Xamarin باشد. اگر تصور شود که از روی تعصب صحبتی میکنم باید بگویم که اتفاقا اگر تعصبی هم وجود داشته باشد نسبت به سی شارپ است نه جاوا. 
در مورد بحث CrossPlatform و کاهش هزینه‌ها برای شرکتهای کوچک و با بودجه محدود به طور حتم Xamarin برنده است. اما شرکتهای بزرگ اغلب رغبتی به استفاده از Xamarin ندارند. برای مثال تلگرام...
البته استفاده بنده از Xamarin قبل از خریداری آن توسط مایکروسافت هست و امیدوارم با کار مایکروسافت روی این تکنولوژی دیگر خبری از باگهای عجیب و غریبی که بنده را فراری دادند نباشد و بتوانم با زبان بسیار عالی و دوست داشتنی سی شارپ هم app موبایل تولید نمایم.(برای نرم افزارهای موبایل سازمانی انتخاب مناسبی هست)
مطالب
توسعه برنامه‌های Cross Platform با Xamarin Forms & Bit Framework - قسمت هفتم
در قسمت ششم، یک صفحه ساده برای لاگین نوشتیم که عملا کار خاصی نمی‌کرد. حال می‌خواهیم در این قسمت روی UI آن کمی کار کنیم. دقت کنید که هدف این قسمت، آموزش زیبا سازی صفحات نیست؛ بلکه هدف، آشنایی شما با تنظیمات مهم UI است.
صفحه Login ای که در قسمت قبل نوشته شد، خود یک Content Page است و دارای یک Stack Layout با چینش عمودی است. داخل آن دو Entry برای گرفتن نام و نام کاربری وجود دارد و یک Button.
مشکلی که صفحه لاگین دارد این است که اگر در یک تبلت 10 اینچی هم باز شود، عرض Entry‌ها و Button هم 10 اینچ می‌شوند که ما قطعا این را نمی‌خواهیم. اینکه چه می‌خواهیم خود یک سوال است! ولی یکی از راه‌های متداول و آسان که برای صفحه لاگین هم قابلیت استفاده دارد این است که از المان‌های صفحه درخواست می‌شود مثلا 5 سانتی متر باشند. حال اگر صفحه نمایش بیشتر از 5 سانتی متر فضا داشت، دلیلی و ارزشی برای بیشتر بزرگ شدن المان‌های روی صفحه نیست. البته اگر صفحه نمایش کوچک‌تر از 5 سانتی متر هم باشد، اینکه المان‌های روی صفحه اصرار به 5 سانتی متر ماندن کنند، نتیجه جالبی نخواهد داشت! برای دستیابی به بهترین نتیجه، شما می‌توانید از WidthRequest و HeightRequest استفاده کنید. وقتی WidthRequest را برابر با 5 سانتی متر قرار دهید، در واقع دارید درخواست می‌کنید که این مقدار شود. اگر فضا بیشتر شود، المان مربوطه بزرگ‌تر از 5 سانتی متر نخواهد شد. اگر فضا کل فضایی که دارد، کمتر از 5 سانتی متر باشد و مثلا 4 سانتی متر باشد، آن هم 4 سانتی متر خواهد شد.
برای شروع سؤال پیش می‌آید که این WidthRequest را به کدامیک از Tag‌ها بدهیم؟ Content Page یا Stack Layout یا هر کدام از Entry‌ها و Button لاگین؟ اساسا وظیفه Layout به عهده Page نیست. در اکثر مواقع، اینکار با خود Stack Layout انجام می‌شود ( یا در سایر مثال‌ها با Grid - Flex Layout و ... ) تنظیم WidthRequest برابر با 5 سانتی متر، آن هم برای تک تک Entry‌ها و Button مربوطه هم اساسا ایده جالبی نیست.
برای این که Width Request برابر با 5 سانتی متر شود، باید به آن مقدار 320 داده شود. هر 64 تا می‌شود یک سانتی متر و 320 = 64 * 5
اگر Width Request را در مثال Login برابر با 320 قرار دهید، می‌بینید که کوچک نمی‌شود و کماکان کل فضای صفحه را می‌گیرد! علت این است که هر المان روی صفحه، از جمله Stack Layout، علاوه بر WidthRequest و HeightRequest که عرض و طول Child را نسبت به Parent مشخص می‌کند، دارای VerticalOptions و HorizontalOptions نیز هست. VerticalOptions و HorizontalOptions در کنار WidthRequest و HeightRequest، رابطه بین یک Parent و Child را مشخص می‌کنند (در این مثال رابطه بین Content Page و Stack Layout به عنوان Parent و Child). به صورت پیش فرض هر Child ( در اینجا Stack Layout ) به صورت عمودی و افقی Parent اش ( در اینجا Content Page ) را Fill می‌کند. علت پیش فرض بودن این رفتار این است که کمترین سربار ممکن را از لحاظ Performance دارد و خیلی از جاها هم مفید است. در اینجا چون Stack Layout قصد دارد Parent خود را Fill کند، دیگر WidthRequest برایش معنی ندارد. در ادامه من VerticalOptions را برابر با Start و HorizontalOptions را برابر با Center می کنم. این باعث می‌شود که Stack Layout ما از لحاظ عمودی در بالا و از لحاظ افقی در وسط Content Page قرار بگیرد و بیش از پنج سانتی متر بزرگ نشود و در صورتیکه Content Page خود فضای کمی داشته باشد ( مثلا در یک گوشی موبایل با صفحه نمایش خیلی کوچک باشد )، Stack Layout حتی از پنج سانتی متر کوچک‌تر هم می‌شود.
دقت کنید که دو Entry و Button داخل Stack Layout نیز Fill هستند، پس داخل Parent خود یعنی Stack Layout را پر می‌کنند. اگر به Stack Layout یک Background دهید، درک بهتری از آن چه که دارد اتفاق می‌افتد، خواهید داشت.
<StackLayout
      BackgroundColor="LightYellow"
      HorizontalOptions="Center"
      Orientation="Vertical"
      VerticalOptions="Start"
      WidthRequest="320">

مشکل دیگری که وجود دارد این است که اگر بابت کمبود فضا، Stack Layout کوچکتر از 5 سانتی متر شود، از بغل، کامل، به کناره‌های Parent خود می‌چسبد که اصلا جالب نیست. برای رفع این مشکل می‌توانیم از Padding (حاشیه داخلی) و Margin (حاشیه خارجی) استفاده کنیم. در عکس زیر، Background مربوط به Content Page را قرمز و Stack Layout را آبی کرده‌ایم. با اختصاص دادن یک سانتی متر (64) به Padding و نیم سانت به Margin، می‌توانید در عکس زیر تاثیر آن را ببینید:

در سمت راست، بالا و چپ Stack Layout، به اندازه نیم سانت حاشیه قرمز می‌بینید که تاثیر Margin است. همچنین المان‌های داخل Stack Layout نیز هر کدام یک سانت از اطراف فاصله دارند که تاثیر Padding است. در پایین Stack Layout، تا جایی که Content Page بزرگ شود، فضای قرمز می‌بینید، نیم سانت از این فضای قرمز به خاطر Margin بوده، ولی باقی مربوط به این است که VerticalOptions را برای Stack Layout، بر روی Start تنظیم کرده‌ایم که باعث می‌شود Stack Layout بالای Content Page قرار بگیرد و زیر آن تماما قرمز شود. حتی اگر "عرض" صفحه نمایش بزرگتر از عکس قبلی می‌بود، فضای قرمز از راست و چپ بیشتر می‌شد که نیم سانت آن بابت Margin بوده و بیشتر از آن مربوط به HorizontalOptions است که برای Stack Layout روی Center تنظیم شده.

با توجه به اینکه Page - Layout - Control‌ها در Android-iOS-Windows به معادل‌های Native خود تبدیل می‌شوند و برای مثال ظاهر Button در این سه پلتفرم متفاوت است، ممکن است Padding ای که به یک کنترل داده ایم و در اندروید خوب به نظر می‌رسد، در iOS مقدار دیگری را لازم داشته باشد. مثلا در Android مقدار 2 و در iOS مقدار 3 لازم داشته باشد. یا ممکن است این مقدار به ازای این که در موبایل، تبلت یا دسکتاپ باشیم، لازم باشد که متفاوت باشد. در Xaml ما دو امکان OnPlatform و OnIdiom را داریم که هر Property اعم از Font Size - Padding - Text و ... را می‌توان به ازای هر شرایطی با مقداری متفاوت مقدار دهی نمود. برای مثال داریم:

<StackLayout
        Margin="{OnPlatform Android=3,
                            iOS='0,0,20,0',
                            UWP='2'}"
        Padding="{OnIdiom Default=2,
                          Tablet=3}" ...

البته Property‌های مهم دیگری نیز در UI تاثیر گذار هستند. برای مثال Opacity برای تنظیم شفافیت، FlowDirection برای تنظیم Right to left و Left to right بودن و خیلی Property‌های دیگه که به مرور و با بیشتر کار کردن با Xamarin Forms با آن‌ها آشنا می‌شوید.

در قسمت بعدی به نوشتن منطق می‌پردازیم؛ نحوه نمایش دادن خطا و رفتن از صفحه‌ای به صفحه‌ی دیگر.