NGame

توسعه دهنده
  • تعداد ارسال ها

    23
  • تاریخ عضویت

  • آخرین بازدید

  • روز های برد

    23

آخرین بار برد NGame در 28 شهریور

NGame یکی از رکورد داران بیشترین تعداد پسند مطالب است!

اعتبار در سایت

79 فوق العاده

4 دنبال کننده

درباره NGame

  • درجه
    کاربر
  • تاریخ تولد 5 مرداد 1373

اطلاعات نمایه

  • جنسیت
    آقا
  • سیستم عامل کامپیوتر
    Windows 10
  • سیستم عامل موبایل
    Windows 10
  • موبایل
    Nokia Lumia 920

اطلاعات تماس

  • مرورگر
    Microsoft Edge

آخرین بازدید کنندگان نمایه

198 بازدید کننده نمایه
  1. مشکل حل شد . اومدم رو وی پی اس دیتابیس ساختم با ریموت بهش وصل شدم و خود انتیتی فرمورک رو مستقیم بهش وصل کردم حل شد
  2. سلام خسته نباشید . دوستان من چند وقته کار با Asp.Net MVC رو شروع کردم ولی به شدت با دیتابیس مشکل دارم به طوری که همه چی روی پی سی اوکی و بدون مشکل هست زمانی که رو هاست میره پروژه به هیچ عنوان به اسکیوال سرور کانکت نمیشه و تو این چند روز دست کم 150 تا ارور کاملا متفاوت رو شاهد بودم اگه میشه یه آموزش از ساخت یه دیتابیس خیلی مبتدی در همین حد که مثلا یه نام از کاربر بگیره ثبت کنه بزارید تو انجمن از ابتدا تا جایی که پروژه رو روی هاست یا VPS میزارید و کانکشن دیتابیس رو درست کنید . هر چی سرچ کردم و هر چی تست کردم حاصل فقط ارور جدید بود مرسی اه
  3. والا از من که اصلا اپل آی دی نخواست ! فیلتر شکن هم استفاده نکردم چه کردی که اپل ای دی خواسته ازت
  4. c#

    جواب کل سوالاتت تو سه خط کد : MPE.Source = Windows.Media.Core.MediaSource.CreateFromUri(new Uri("http://....", UriKind.RelativeOrAbsolute)); MPE.MediaPlayer.Play(); MPE.MediaPlayer.Pause(); //MPE = MediaPlayerElement
  5. استفاده از جیسون کار ساده ای هست . بستگی به سمت سرور داره اگه ASP باشه یه تابع برا اینکار داره به اسم Json اگر اشتباه نکنم . یادم نیست یک ساله تقریبا کار نکردم یادم رفته . توی نوگت های زمارین فرم هم یه نوگت هست NewthonSoft Json معمولا همون اولین نوگت میاد انقد پر کاربرده . اموزش کار باهاش هم یه سرچ کنی هست
  6. آموزش کار با Navigationbar در Xamarin.Forms همانطور که در آموزش قدم به قدم برنامه نویسی Xamarin.Forms نیز اشاره کردم یکی از انواع صفحات موجود در زمارین فرم NavigationPage میباشد . به صورت پیشفرض این صفحه در بالای هر صفحه یک کادر حاوی عنوان صفحه و کلید بازگشت به صفحه قبل نشان میدهد . در این آموزش خواهیم آموخت چطور این صفات را تغییر دهیم . 1 - پنهان کردن کامل نوار بالا در یک صفحه : در صفحه مورد نظر خود کد زیر را جهت عدم نمایش NavigationBar وارد کنید : NavigationPage.SetHasNavigationBar(this, false); و جهت نمایش مجدد آن از کد زیر استفاده کنید : NavigationPage.SetHasNavigationBar(this, true); 2 - جهت عدم نمایش کلید بازگشت در NavigationPage : NavigationPage.SetHasBackButton(this, false); جهت نمایش مجدد : NavigationPage.SetHasBackButton(this, true); نکته : اگر صفحه ای صفحه نخست باشد true کردن نمایش کلید بازگشت باعث نمایش این کلید نخواهد شد . نکته : اگر صفحه ای کلید بازگشت از آن محو شود باعث از کار افتادن عملکرد کلید بازگشت دستگاه های اندروید و ویندوز فون نخواهد شد .
  7. هم از لحاظ امنیتی هم از لحاظ مواجه شدن با مشکلات اصلا کار درستی نیست که به صورت مستقیم با دیتابیس کار کنید . شما باید یک WebApi بنویسید که از طریق اون به سرور درخواست بدید سرور از روی دیتابیس اطلاعات مورد نظر رو برای شما به صورت JSON یا XML ارسال کنه . در گذشته XML خیلی کاربرد داشت ولی الان تقریباً همه JSON استفاده میکنن چون کوتاه تر هست و حجم اطلاعات ارسالی و دریافتی کمتره . پایگاه داده سمت سرور هم قاعدتاً Oracle یا SQL Server (ترجیحاً ورژن 2016) باشه نتیجه بهتری میگیرید .
  8. آموزش برنامه نویسی با Xamain.Forms قسمت هفتم: کار با لیست ویو لیست ویو Incremental Loading در این قسمت آموزش قصد دارم به شما نشون بدم که چطور میتونید یک لیست بسازید که به صورت خودکار آیتم های بیشتری لود کنه . این نوع لیست ویو چه کاربردی داره و چه زمانی از اون استفاده میکنیم ؟ این نوع لیست برای زمان هایی کاربرد داره که لیست ما احتمالا طولانی شدن اون زیاد هست یا حجم داده ها به هر نحوی زیاد هست یا اصلا اطلاعاتی که از سرور دریافت میکنیم به صورت صفحه به صفحه است و در هر صفحه به عنوان مثال 10 یا 20 آیتم جدید به ما برگردونده میشه . در اینجا من یک برنامه ساده میسازم که فقط یک متن ساده همراه با عکس دریافت میکند و به کاربر نشان میدهد . ابتدا یک لیست ویو میسازیم . برای سادگی کار از ItemTemplate برای استایل دادن به آیتم های درون لیست استفاده میکنیم . <ListView x:Name="Lst" > <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Grid BackgroundColor="LightCyan"> <Grid.ColumnDefinitions> <ColumnDefinition Width="87"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Grid Grid.Column="0"> <Image Grid.Column="0" Margin="0,7.5" HeightRequest="70" WidthRequest="70" Source="{Binding Img}" Aspect="AspectFit" VerticalOptions="Fill" HorizontalOptions="Fill" /> </Grid> <StackLayout Grid.Column="1" VerticalOptions="Center"> <Label Text="{Binding Text1}" FontAttributes="Bold" /> <Label Text="{Binding Text2}" TextColor="#FF646464" FontAttributes="Italic" /> <Label Text="{Binding Text3}" TextColor="#FF646464" Margin="0,0,10,0" FontAttributes="Bold"/> </StackLayout> </Grid> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> همونطور که مشاهده میکنید لیست ویو یک لیست کاملاً ساده هست و همونطوری ساخته شده که توی برنامه نویسی UWP و WPF هم لیست ویو میسازیم با این تفاوت که داخل DataTemplate یک ViewCell هم باید بگزاریم . کار ما سمت XAML تموم شده حالا میریم داخل کد های سی شارپ . حال یک کلاس برای بایند کردن Template به لیست میسازیم به صورت زیر : public class OurLstItems { public string Img { get; set; } public string Text1 { get; set; } public string Text2 { get; set; } public string Text3 { get; set; } } حال یک ObservableCollection از همین کلاس میسازیم . یکی از خاصیت های اصلی ObservableCollection این هست که در صورت اضافه و کم شدن آیتم به صورت خودکار UI نیز آپدیت میشود پس برای راحتی از همین نوع کالکشن استفاده میکنیم و آنرا به صورت یک متغیر سراسری در پیج معرفی میکنیم . ObservableCollection<OurLstItems> items = new ObservableCollection<OurLstItems>(); همچنین جهت عکس یک عکس نمونه کوچک را انتخاب کردم که به شکل سراسری در پروژه تعریف مینماییم . const string image = "http://files.softicons.com/download/system-icons/othoni-afis-icons-by-steven-zangh/png/60x60/Settings.png"; استراتژی جهت لود آیتم های جدید ! برای لود کردن آیتم های جدید لیست باید یک استراتژی در نظر بگیریم که چه زمانی باید ایتم های جدید را لود کنیم . در صورتیکه اطلاعات از اینترنت دریافت میشوند و همانطور که میدانید ممکن است سرعت اینترنت خصوصاً در ایران در بسیاری مواقع پایین باشد لذا لازم است سریع تر این کار را انجام دهیم و گاهی که به عنوان مثال از حافظه دستگاه اطلاعات استخراج میشود با رسیدن به انتهای لیست نیز میتوان این کار را کرد ! به عنوان یک استاندارد من در کد خودم در هر صفحه 20 آیتم جدید تولید میکنم و به برنامه تحویل میدهم (که در سایت های خبری ، موزیک و .... نیز معمولا تعداد آیتم ها 10 ، 15 یا 20 مورد در نظر گرفته میشوند.) private List<OurLstItems> GenerateNewItems() { return new List<OurLstItems>() { new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, }; } حال در Constructor برنامه کالکشن خود را به لیست ویو بایند میکنیم Lst.ItemsSource = items; در لیست ویو های زمارین دو Event به نام های ItemAppearing و ItemDisappearing از این دو تا ایونت جهت فهمیدن اینکه چه آیتمی در حال محو شدن از دید کاربر هستند یا بلعکس چه آیتم هایی در حال اضافه شدن به ویوی برنامه میباشند . تفاوت این دو ایونت در این است که یکی به ابتدای صفحه اشاره دارد و دیگری به انتهای صفحه . اگر میخواهید استراتژی لود آیتم ها به صوتی باشد که در صورت نزدیک شدن به آیتم های پایانی لیست ایتم های جدید لود شود بهتر است از ItemAppearing استفاده نمائیم . همچنین استفاده همزمان از هر دو ایونت میتواند به ما نشان دهد که در گوشی کاربر به صورت همزمان چند آیتم به نمایش در می آید . من در اینجا از ItemAppearing استفاده میکنم و استراتژی به این صورت خواهد بود که 15 آیتم به پایان لیست آیتم های جدید لود خواهم کرد . private void Lst_ItemAppearing(object sender, ItemVisibilityEventArgs e) { var item = e.Item as OurLstItems; var index = items.IndexOf(item); if(items.Count - index <= 15) foreach (var IOA in GenerateNewItems()) { items.Add(IOA); } } کار تمام است فقط به این دلیل که در ابتدای اجرای برنامه آیتمی در لیست وجود ندارد لذا در حین اجرای برنامه هم این سه خط را مینویسیم تا برنامه به درستی کار کند . foreach (var item in GenerateNewItems()) { items.Add(item); } به این ترتیب کد نهایی برنامه ما به صورت زیر خواهد بود : public partial class MainPage : ContentPage { public class OurLstItems { public string Img { get; set; } public string Text1 { get; set; } public string Text2 { get; set; } public string Text3 { get; set; } } const string image = "http://files.softicons.com/download/system-icons/othoni-afis-icons-by-steven-zangh/png/60x60/Settings.png"; ObservableCollection<OurLstItems> items = new ObservableCollection<OurLstItems>(); public MainPage() { InitializeComponent(); Lst.ItemsSource = items; foreach (var item in GenerateNewItems()) { items.Add(item); } } private List<OurLstItems> GenerateNewItems() { return new List<OurLstItems>() { new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, new OurLstItems(){ Img = image, Text1 = $"First{new Random().Next()}", Text2 = $"Second{new Random().Next()}",Text3 = $"Third{new Random().Next()}"}, }; } private void Lst_ItemAppearing(object sender, ItemVisibilityEventArgs e) { var item = e.Item as OurLstItems; var index = items.IndexOf(item); if(items.Count - index <= 15) foreach (var IOA in GenerateNewItems()) { items.Add(IOA); } } } خروجی کار : اگر در تصویر فوق دقیق شوید متوجه خواهید شد که با نسخه UWP تفاوت فراوانی دارد هم آیکن ها کوچک تر هستند و هم خط سوم Text3 نمایش داده نمیشود ! برای حل این مشکل تنها کافیست در کد های XAML یک مشخصه به لیست ویو اضافه نمائید . HasUnevenRows یعنی کد زمل به صورت زیر تغییر خواهد کرد . <ListView x:Name="Lst" ItemAppearing="Lst_ItemAppearing" HasUnevenRows="True"> ..... </ListView>
  9. این راه اگه جواب نده راهش BackgroundMediaPlayer هستش . باید یک Windows Runtime Component بسازی که به اون مسج بزنی از فورگراند اون اجرا کنی . خواه ناخواه یک مقدار پیچیده هست ذاتاً روشش . در ضمن این روش که رامتین معرفی کرده برای بیلد 14393 به بعد فقط جواب میده البته مطمئن نیستم . تو داکیومنت مایکروسافت فک کنم نوشته بود 14393 میخواد
  10. آموزش برنامه نویسی با Xamain.Forms قسمت ششم : استایل دهی به آبجکت ها در هر پلتفرم توی این قسمت از آموزش میپردازیم به بحث Custom Renderer قبل از هر چیزی باید بدونیم CustomRenderer چی هست و چه زمان باید بریم سراغش همینطور که در متن بالا هم قابل مشاهده هست برای هر کنترل (یا به عبارتی آبجکت) توی زمارین یک Renderer هم براش وجود داره که بهتره از همون دیفالتش استفاده کنیم اما برای جاهایی که امکان تغییر یک مشخصه از آبجکت برای ما وجود نداره باید خودمون دست به کار بشیم و تغییرات رو خودمون اعمال کنیم . نمونه هایی از جاهایی که نیاز هست از Custom Renderer استفاده کنیم : 1 - گرد کردن گوشه های کادر های ورودی کاربر (Entry) 2 - انتخاب یک پس زمینه گرادیانت برای صفحه و.... برای مثال عملی با همین گرد کردن کادر دور Entry شروع میکنیم . توی پروزه مشترک زمارین یک پوشه به اسم StyledObjects که آبجکت هایی که بهشون استایل میدیم رو اونجا ذخیره میکنیم . البته اسم پوشه کاملاً دلخواه هستش. یک کلاس داخل پوشه به اسم CSRoundedEntry بسازید که مخفف Custom Styled Rounded Entry میباشد . مشخصه هایی که برای آبجکت مد نظرتون در نظر دارید (علاوه بر مشخصه های پیشفرض آبجکت اصلی) داخل این کلاس تعریف کنید . دقت کنید این کلاس باید از آبجکت اصلی ارث بری شده باشد . به عنوان مثال : namespace GettingStarted.StyledObjects { class CSRoundedEntry : Entry { public int CornerRadious { get; set; } } } همانطور که در کد بالا قابل مشاهده است با استفاده از Entry : کلاس من از خواص Entry ارث بری شده و وارث خواص این کلاس است علاوه بر اینکه یک مشخصه به نام Corner Radious جهت میزان زاویه خمیدگی در نظر گرفتم . حالا باید دقیقاً مثل بحث قبلی که بحث DependencyServices بود باید در هر پروژه یک کلاس برای این آبجکت ایجاد نمائیم . در پروژه اندروید یک کلاس مانند زیر ایجاد میکنیم [assembly: ExportRenderer(typeof(GettingStarted.StyledObjects.CSRoundedEntry), typeof(GettingStarted.Droid.StyledObjects.CSRoundedEntry))] namespace GettingStarted.Droid.StyledObjects { class CSRoundedEntry : EntryRenderer { } } خب همونطور که در بالا هم مشاهده میشه کاستوم رندرر هم خیلی شبیه به Dependency Service ها هست با این تفاوت که چون از اینترفیس ارث بری نشده در ExportRenderer هم کلاس اصلی در پروژه ی مشترک رو ذکر میکنیم هم کلاسی که همینجا مینویسیم و به این طریق این دو کلاس رو به هم ربط میدیم . حالا در کلاس یک تابع وجود داره که باید اون رو Override کنیم به نام OnElementChanged . داخل کلاس این تابع رو اضافه میکنیم : protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) { this.Control.Background = ContextCompat.GetDrawable(Context,Resource.Drawable.RoundedCornerEntry); } } با استفاده از Control شما به پراپرتی ها (مشخصات) آبجکت دسترسی دارید . این قسمت کار واقعاً نیازمند تسلط به کد نویسی هر سیستم عامل میباشد و امکان اینکه یک نسخه مشترک برای همه سیستم عامل ها بپیچیم وجود نداره . برای اینکه راحت تر بتونیم به آبجکت ها استایل بدیم و اینکه بشه روش نسبتاً مشترکی برای همه سیستم عامل ها گفت من در نسخه اندروید و UWP با استفاده از زبان کد نویسی رابط کاربری خود سیستم عامل ها یک فایل استایل ساختم و اون رو در کد لود میکنم . همونطور که در کد بالا هم مشاهده میکنید Rounded Corner Entry رو از ریسورس های برنامه لود میکنم . پس در پوشه Resources و پوشه Drawable یک فایل xml به نام RoundedCornerEntry.xml ایجاد میکنم که از طریق کد سی شارپ هم این فایل رو فراخونی کردم . اگر Build Action این فایل چیزی جز Android Resource بود بیلد اکشن رو تغییر بدید . داخل فایل استایل مورد نظر خودم رو مینویسم که به شکل زیر هست : <?xml version="1.0" encoding="UTF-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_focused="true" > <shape android:shape="rectangle"> <gradient android:startColor="@color/entry_background" android:endColor="@color/entry_background" android:angle="270" /> <stroke android:width="1dp" android:color="@color/entry_border" /> <corners android:radius="6dp" /> </shape> </item> <item> <shape android:shape="rectangle"> <gradient android:startColor="@color/entry_background" android:endColor="@color/entry_background" android:angle="270" /> <stroke android:width="1dp" android:color="#c6c6c6" /> <corners android:radius="6dp" /> </shape> </item> </selector> خب اینکه چطور این استایل رو نوشتم هم خیلی ساده اس فقط یک سرچ توی اینترنت زدم ! همین . همینطور اگه تو ریسورس بالا دقت کنید زاویه لبه های کادر رو 6dp در نظر گرفتم و کلا به پراپرتی که به عنوان نمونه اضافه کرده بودم کار نداشتم ! حالا میریم به سراغ ios : توی ای او اس هم دقیقاً مثل همون قضیه Dependency Service و مثل کاری که برای اندروید انجام دادیم مجددا یک کلاس میسازیم و تابع رو override میکنیم : [assembly: ExportRenderer(typeof(GettingStarted.StyledObjects.CSRoundedEntry), typeof(GettingStarted.iOS.StyledObjects.CSRoundedEntry))] namespace GettingStarted.iOS.StyledObjects { class CSRoundedEntry : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) { Control.Layer.CornerRadius = 6; Control.Layer.BorderWidth = new nfloat(2); Control.Layer.BackgroundColor = UIColor.FromRGBA(255, 255, 255, 204).CGColor; Control.TintColor = UIColor.FromRGBA(255, 255, 255, 178); } } } } که همونطور که مشخص هست اینجا هم کاری به کار مشخصه ای که تعریف کردیم نداشتم و باز هم زاویه رو 6 در نظر گرفتم ! حتی نمیدونم چرا اون پراپرتی رو الکی در نظر گرفتم همونطور که توی کد بالا مشخص هست با استفاده از Control.Layer به مشخصات آبجکت دسترسی داریم و میتونیم تغییرات رو اعمال کنیم حالا به سراغ UWP میریم . برای تغییر دادن آبجکت ها توی UWP یک روش بسیار ساده وجود داره . وارد msdn.com بشید سرچ کنید ObjectName Default Style in UWP به عنوان مثال دیفالت استایل مربوط به تکست باکس در این لینک قابل مشاهده هست . دیفالت استایل رو کافیه کپی کنیم و توی فایل app.XAML آنرا کپی کنید . البته ابتدا باید در این فایل چند خط کد اضافه کنید <Application.Resources> <ResourceDictionary> </ResourceDictionary> </Application.Resources> حال باید استایل را در داخل ResourceDictionary کپی کنید و تغییرات مورد نظرتون رو در استایل پیشفرض ایجاد کنید . برای جلوگیری از شلوغ شدن فایل هم پیشنهاد میکنم توی پروژه UWP یک پوشه به اسم Styles ایجاد کنید و یک فایل ResourceDictionary در این پوشه ایجاد کنید و داخل فایل app.XAML این فایل را به صورت زیر لود کنید . <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/Styles/Dictionary1.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> برای مثال من استایل پیشفرض رو به شکل زیر تغییر دادم و در فایل Dictionary1 کپی کردم : <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!-- Default style for Windows.UI.Xaml.Controls.TextBox --> <Style TargetType="TextBox" x:Key="StyleRoundedTextBox"> <Setter Property="MinWidth" Value="{ThemeResource TextControlThemeMinWidth}" /> <Setter Property="MinHeight" Value="{ThemeResource TextControlThemeMinHeight}" /> <Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}" /> <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundAltHighBrush}" /> <Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundChromeDisabledLowBrush}" /> <Setter Property="SelectionHighlightColor" Value="{ThemeResource SystemControlHighlightAccentBrush}" /> <Setter Property="BorderThickness" Value="{ThemeResource TextControlBorderThemeThickness}" /> <Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" /> <Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" /> <Setter Property="ScrollViewer.HorizontalScrollMode" Value="Auto" /> <Setter Property="ScrollViewer.VerticalScrollMode" Value="Auto" /> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" /> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" /> <Setter Property="ScrollViewer.IsDeferredScrollingEnabled" Value="False" /> <Setter Property="Padding" Value="{ThemeResource TextControlThemePadding}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TextBox"> <Grid> <Grid.Resources> <Style x:Name="DeleteButtonStyle" TargetType="Button"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Grid x:Name="ButtonLayoutGrid" BorderBrush="{ThemeResource TextBoxButtonBorderThemeBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{ThemeResource TextBoxButtonBackgroundThemeBrush}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="GlyphElement" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAccentBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Pressed"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ButtonLayoutGrid" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAccentBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="GlyphElement" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAltChromeWhiteBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <DoubleAnimation Storyboard.TargetName="ButtonLayoutGrid" Storyboard.TargetProperty="Opacity" To="0" Duration="0" /> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <TextBlock x:Name="GlyphElement" Foreground="{ThemeResource SystemControlForegroundChromeBlackMediumBrush}" VerticalAlignment="Center" HorizontalAlignment="Center" FontStyle="Normal" FontSize="12" Text="&#xE10A;" FontFamily="{ThemeResource SymbolThemeFontFamily}" AutomationProperties.AccessibilityView="Raw"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </Grid.Resources> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Disabled"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="HeaderContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledChromeDisabledLowBrush}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Normal" /> <VisualState x:Name="PointerOver"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightChromeAltLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Opacity"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundHoverOpacity}" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="Focused"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="PlaceholderTextContentPresenter" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlPageTextChromeBlackMediumLowBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Background"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundChromeWhiteBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="Opacity"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource TextControlBackgroundFocusedOpacity}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="BorderElement" Storyboard.TargetProperty="BorderBrush"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightAccentBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="Foreground"> <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlForegroundChromeBlackHighBrush}" /> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentElement" Storyboard.TargetProperty="RequestedTheme"> <DiscreteObjectKeyFrame KeyTime="0" Value="Light" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="ButtonStates"> <VisualState x:Name="ButtonVisible"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="DeleteButton" Storyboard.TargetProperty="Visibility"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="ButtonCollapsed" /> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Border x:Name="BackgroundElement" Grid.Row="1" Background="{TemplateBinding Background}" Margin="{TemplateBinding BorderThickness}" Opacity="{ThemeResource TextControlBackgroundRestOpacity}" Grid.ColumnSpan="2" Grid.RowSpan="1"/> <Border x:Name="BorderElement" CornerRadius="6" Grid.Row="1" BorderBrush="#ccffffff" Background="#b2ffffff" BorderThickness="2" Grid.ColumnSpan="2" Grid.RowSpan="1"/> <ContentPresenter x:Name="HeaderContentPresenter" x:DeferLoadStrategy="Lazy" Visibility="Collapsed" Grid.Row="0" Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}" Margin="0,0,0,8" Grid.ColumnSpan="2" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" FontWeight="Normal" /> <ScrollViewer x:Name="ContentElement" Grid.Row="1" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" IsTabStop="False" AutomationProperties.AccessibilityView="Raw" ZoomMode="Disabled" /> <ContentControl x:Name="PlaceholderTextContentPresenter" Grid.Row="1" Foreground="{ThemeResource SystemControlPageTextBaseMediumBrush}" Margin="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" IsTabStop="False" Grid.ColumnSpan="2" Content="{TemplateBinding PlaceholderText}" IsHitTestVisible="False"/> <Button x:Name="DeleteButton" Grid.Row="1" Style="{StaticResource DeleteButtonStyle}" BorderThickness="{TemplateBinding BorderThickness}" Margin="{ThemeResource HelperButtonThemePadding}" IsTabStop="False" Grid.Column="1" Visibility="Collapsed" FontSize="{TemplateBinding FontSize}" MinWidth="34" VerticalAlignment="Stretch"/> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary> حالا دوباره مثل نسخه اندروید و آی او اس کلاس مینویسیم و تابع override میکنیم به این شکل : [assembly: ExportRenderer(typeof(GettingStarted.StyledObjects.CSRoundedEntry), typeof(GettingStarted.UWP.StyledObjects.CSRoundedEntry))] namespace GettingStarted.UWP.StyledObjects { class CSRoundedEntry : EntryRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); Control.Style = (Windows.UI.Xaml.Style)GettingStarted.UWP.App.Current.Resources["StyleRoundedTextBox"]; } } } یک نکته خیلی مهم که توی این کد بالا هست اینه که حتماً حتماً حتماً این namespace ها توی کد UWP باشه . چون هم کلمه Style هم App به صورت مشترک در خود UWP و هم در Xamarin.Forms استفاده شده و اگر حواستون نباشه به راحتی این دو تا کلاس با هم اشتباه میشن و به ارور های زمان کامپایل و ران تایم بر میخورید که حتی خیلی وقت ها هم ممکنه اصلا متوجه نشید کجا رو اشتباه کردید که به این خطا ها برخورد کردید . خب باز هم توی کد های بالا میبینید که باز هم اون Corner Radious که تعریف کردم رو ازش استفاده نکردم اما اگر شما نیاز دارید که حتما مقدار اون پراپرتی رو دسترسی داشته باشید بهش به این صورت میتونید بهش دسترسی داشته باشید : protected override void OnElementChanged(ElementChangedEventArgs<Entry> e) { base.OnElementChanged(e); if (Control != null) { var element = (GettingStarted.StyledObjects.CSRoundedEntry)e.NewElement; var rad = element.CornerRadious; } } حالا که آبجکت ما برای هر سه سیستم عامل حاضر شده توی کد های XAML صفحه مورد نظرمون کافیه که ابتدا نیم اسپیس کلاس خودمون رو به پروژه بشناسونیم : xmlns:local="clr-namespace:GettingStarted.StyledObjects" و بعد توی کد های زمل هم مثل خط زیر میشه از آبجکت خودمون استفاده کنیم و پراپرتی های مورد نظرمون رو هم به دلخواه مقدار دهی کنیم : <local:CSRoundedEntry Placeholder="passwod" FontSize="20" HeightRequest="50" IsPassword="True" CornerRadious="6"/>
  11. ببخشید من یه مشکلی کلا با این Transport Controls دارم اونم اینکه یه بار یکی از کلیداش رو بزنی بعد چند دقیقه دیگه کلا کلید هاش از کار میافته اگه دوباره کلیدی نزده باشی . یکم سرچ کردم دیدم با AutoResetEvent و ManualResetEvent انگار باید حلش کرد ولی بازم نتونستم مشکل رو حل کنم . راه حلی داری براش ؟
  12. آموزش برنامه نویسی با Xamain.Forms قسمت پنجم : کد نویسی اختصاصی هر سیستم عامل ! (بخش دوم) همانطور که توی قسمت قبل اشاره شد زمارین از امکانی جهت کد نویسی مخصوص هر سیستم عامل پشتیبانی میکنه . توی قسمت قبل به یک نمونه بسیار ساده پرداختیم که با استفاده از اون میشد متناسب با هر سیستم عامل پیغام مناسب به کاربر نشون بدیم که یکی از ویژگی های بسیار ساده بود . اما توی این قسمت میخوایم یک مقدار حرفه ای تر با Dependency Services کار کنیم و ببینیم واقعاً کجا ها کاربرد داره . قطعاً میدونید که هر سیستم عامل یک سری api مخصوص به خودش رو داره که احتمالا هنوز توی Xamarin.Forms پیاده سازی نشده که نمونه های بسیار بسیار زیادی از این رو میشه توی پلتفرم جدید UWP مشاهده کرد . امکاناتی مثل LiveTile یا کاشی زنده یا ساده تر حتی بستن یک برنامه یا پخش یک فایل موزیک و.... در اینجا چند نمونه کد برای نمونه قرار میدم که از Dependency Services استفاده کردم . کد اول جهت بستن برنامه هست . روش استفاده از این متد هم همونطور که توی قسمت قبل اشاره شد خیلی ساده هست DependencyService.Get<ICloseApplication>().CloseApplication(); خب ابتدا از روی فرمت دستوری که بالا نوشتم مشخصه که اینترفیس مورد نیاز برای کلاس بالا خیلی ساده یک تابع به اسم CloseApplication داره بدون هیچ پارامتری : public interface ICloseApplication { void CloseApplication(); } کلاس بستن برنامه برای اندروید : [assembly:Dependency(typeof(AppCloser))] namespace GettingStarted.Droid.Classes { class AppCloser : ICloseApplication { void ICloseApplication.CloseApplication() { var activity = (Android.App.Activity)Forms.Context; activity.FinishAffinity(); } } } کلاس بستن برنامه برای IOS : [assembly:Dependency(typeof(AppCloser))] namespace GettingStarted.iOS.Classes { class AppCloser : ICloseApplication { public void CloseApplication() { Thread.CurrentThread.Abort(); } } } کلاس بستن برنامه برای UwP و ویندوز فون 8.1 به بالا : [assembly: Dependency(typeof(ClassApp))] namespace GettingStarted.UWP.Classes { class ClassApp : ICloseApplication { public void CloseApplication() { Windows.UI.Xaml.Application.Current.Exit(); } } } یک کلاس دیگه هم اینجا براتون به اشتراک میگذارم کلاس مربوط به اجرای برنامه در Main Thread هر سیستم عامل هست . نحوه استفاده از این کلاس به این شکل هست که دستورات خودتون رو داخل delegate مینویسید ، اگر هم خواستید از دستورات async استفاده کنید به مثل HttpClient یا ... کافیه قبل از delegate کلمه کلیدی async رو اضافه کنید و به صورت async delegate استفاده کنید . به این صورت امکان استفاده از دستورات async به سادگی براتون فراهم میشه . DependencyService.Get<IMainThreedRunner>().Run( /*async if needed*/ delegate { //Your Codes Here; }); برای پیاده سازی اینترفیس کلاس بالا به شکل زیر عمل میکنیم : namespace GettingStarted.Classes { public interface IMainThreedRunner { void Run(Action act); } } کلاس ویژه برای اندروید : [assembly: Dependency(typeof(MainThreedRunner))] namespace GettingStarted.Droid.Classes { class MainThreedRunner : IMainThreedRunner { public void Run(Action act) { new Activity().RunOnUiThread(() => { act.Invoke(); }); } } } کلاس ویژه IOS : [assembly: Dependency(typeof(MainThreedRunner))] namespace GettingStarted.iOS.Classes { class MainThreedRunner : IMainThreedRunner { public void Run(Action act) { UIApplication.SharedApplication.InvokeOnMainThread(delegate { act.Invoke(); }); } } } و در نهایت کلاس ویژه UWP : [assembly: Dependency(typeof(MainThreedRunner))] namespace GettingStarted.UWP.Classes { class MainThreedRunner : IMainThreedRunner { public async void Run(Action act) { await GettingStarted.UWP.MainPage.Dispatch.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, delegate { act.Invoke(); }); } } } در کد بالا به جای MainPage.Dispatcher میتوانید از Windows.UI.Xaml.Window.Current.Dispatcher نیز استفاده کنید که روش بهتری هم هستش ! به همین روش میشه هر کدی رو به میل خودمون توی سیستم عامل های مختلف اجرا کنیم و برای به اشتراک گذاشتن کد هم فقط کافیه مثل بالا اینترفیس و کلاس های مربوط به هر سیستم عامل رو منتشر کنیم . توی قسمت بعدی آموزش به سراغ Custom Renderer خواهیم رفت که کار با خود Custom Renderer مثل تلفظ اسمش یه مقدار مشکله !!! این که چه زمانی باید از Custom Renderer کرد بحثی هست که در قسمت بعدی آموزش بهش میرسیم .
  13. تشکر از پوریا بابت آموزش . یک سری نکات : اگر موقع ایجاد ماشین مجازی توی VirtualBox گزینه های 64 بیتی نداشتید دلیل فعال بودن هایپر وی هست قبل انجام آموزش هایپر وی رو به روش ذکر شده توی مطلب غیر فعال کنید از محیط No Hyper-V بوت کنید ویندوز رو . برای اشتراک گذاری فایل بین ویندوز و مک خیلی ساده هست . گزینه سرچ بالا سمت راست صفحه دسکتاپ مک رو انتخاب کنید ، برنامه Terminal رو جستجو و اجرا کنید . بعد دستور زیر را تایپ کنید ipconfig getoption en0 router یک آدرس آی پی احتمالاً با شروع 10 مثل 10.0.2.2 به شما میده که توی Finder > Go > Connect to server دقیقاً همون رو تایپ کنید بعد یوزر ویندوز و پسوردتون رو بزنید (اگر Pin هم دارید باز هم باید پسورد رو وارد کنید Pin رو قبول نمیکنه) به فولدر های شیر شده از ویندوز دسترسی دارید . برای شیر کردن فولدر کافیه توی ویندوز روی یک پوشه راست کلیک کنید بعد Properties سربرگ Sharing وارد شوید روی Advanced Sharing کلیک کنید سپس تیک Share this folder را بزنید یک نام برای فولدر در حالت Share انتخاب کنید و سپس اوکی کنید . (این کار برای درایو ها نیز قابل انجام است اما جهت امنیت سایر اطلاعات و مخفی ماندن از دید سایر نود های موجود در شبکه بهتر است یک پوشه مشترک تنها برای این امر ایجاد کنید) برای نصب کردن xcode اول حتما فایلش رو توی محیط مک کپی کنید سعی نکنید از روی شبکه مستقیم بخواید اجراش کنید . ترجیحاً روی دسکتاپ مک کپی کنید بعد اجرا کنید منتظر بمونید تا نصب بشه . بعد ویژوال استدیو رو هم به همین روش نصب کنید (تقریباً 2 گیگ دانلود میکنه و برای کار ما فقط Xamarin.Ios کافیه) بعد از نصب هر دو تا مورد مک رو Shutdown کنید به تنظیمات ماشین مجازی تو Virtualbox برید به تنظیماتش بعد قسمت Network توی سربرگ Adapter 2 رفته و تنظیمات زیر را در این قسمت ست کنید . حال مجدداً مک را راه اندازی کنید . حال Remote login را جستجو کنید و آنرا اجرا کنید . سپس تیک Remote login را بزنید و گزینه All Users را انتخاب کنید . بعد از راه اندازی مک به ویژوال استدیوی ویندوز رفته و از tools -> Options Xamarin -> ios settings حال گزینه Find Xamarin Mac را بزنید و Next کنید حال باید به صورت خودکار مک شناسایی شود . روی آن دوبار کلیک کنید و یوزر نیم و پسورد مک را وارد کنید کار تمام است . در صورت مشاهده پیامی مبتنی بر لایسنس xcode در ترمنینال عبارت های زیر را تایپ کنید . sudo xcode-select -s /XcodePath/Xcode-Beta.app/Contents/Developer sudo xcodebuild -license به عنوان مثال اگر در همان صفحه دسکتاپ فایل نصب را کپی و اجرا کرده باشید (که مسیر نصب هم همانجا خواهد بود) دستور اول به صورت زیر خواهد بود sudo xcode-select -s /Users/Usernae/Desktop/Xcode-Beta.app/Contents/Developer بخ جای xcode-beta.app هم اسم فایل برنامه رو باید بنویسید
  14. آموزش برنامه نویسی با Xamain.Forms قسمت چهارم : کد نویسی اختصاصی هر سیستم عامل ! با توجه به امکانات بسیار عالی زمارین فرم باز هم در بسیاری از قسمت ها نیاز داریم که از امکانات اختصاصی پلتفرم ها استفاده کنیم یکی از بارز ترین این استفاده ها نوشتن کد های مربوط به پخش مدیا در پس زمینه میباشد . باید بگم که این قسمت از آموزش یکی از مهم ترین و اصلی ترین قسمت های آموزش میباشد پس به دقت مراحل را انجام دهید . به عنوان یک نمونه خیلی ساده در این آموزش میخواهیم یک پیام خوش آمد ساده به کاربر نشان دهیم اما بسته به اینکه برنامه در چه پلتفرمی اجرا میشود پیغام متفاوتی نمایش داده شود . برای انجام این کار ابتدا نیاز به ساخت یک Interface داریم . در پروژه مشترک زمارین ابتدا یک پوشه به نام دلخواه ایجاد نمائید به عنوان مثال Services یا Classes در پوشه ایجاد شده یک کلاس به نام دلخواه مانند WelcomeMsg بسازید . کلاسی به صورت زیر برای شما ایجاد میشود . class WelcomeMsg { } حال کلاس فوق را به صورت تغییر دهید تا تبدیل به interface شود. public interface IWelcomeMsg { } به دلیل اینکه قواعد کد نویسی سی شارپ را نیز رعایت کرده باشیم ابتدای نام یک I (آی) بزرگ اضافه میکنیم که بیانگر اینترفیس باشد . حال درون آن به تعریف توابعی که در این اینترفیس موجود میباشد میپردازیم . در اینجا تنها کافیست که به امضای تابع و متغیر های پابلیک تعریف شده اشاره کنید و نیازی به نوشتن هیچ کدی نیست . public interface IWelcomeMsg { string GetWelcomeMessage(); } خب به همین سادگی اینترفیس ما ساخته شده و آماده است ! حال باید در تمامی پروژه های مرتبط به تک تک سیستم عامل ها یک پوشه با نام پوشه ای که در پروژه ساختید ایجاد نمائید و کلاسی نیز با همان نام ایجاد نمائید . (هرچند اجباری در این نام گذاری ها نیست اما به جهت جلوگیری از پیچیده شدن کار بهتر است از همین شیوه استفاده نمائید) به عنوان مثال در پروژه UWP در پوشه Services یک کلاس با نام WelcomeMsg ایجاد مینمائیم . پس از ساخته شدن فایل لازم هست که کلاس خودمون رو به اینترفیس ساخته شده متصل نمائیم و برای این کار از خاصیت ارث بری سی شارپ استفاده میکنیم class WelcomeMsg : IWelcomeMsg { } قطعا خواهید دید که از IWelcomeMsg ارور گرفته میشود . اشاره گر موس را روی IWelcomeMsg قرار دهید و روی علامت چراغ زرد رنگ ظاهر شده کلیک کنید و سپس Implement Interface را انتخاب کنید . حال به صورت خودکار توابع تعریف شده در اینترفیس اینجا تعریف خواهند شد . class WelcomeMsg : IWelcomeMsg { public string GetWelcomeMessage() { throw new NotImplementedException(); } } خط throw new NotImplementedException(); به این منظور به صورت خودکار ایجاد میشود تا در صورت فراخوانی تابع Debugger به خطا برخورد کند و به شما اخطار دهد که این تابع کد نویسی نشده ! در اینجا به این خط نیازی نداریم و آنرا پاک میکنیم و به جای آن پیام خود را مینویسیم مانند : return "Welcome to our UWP Xamarin App"; حال در خط اول کلاس پیش از namespace و بعد از using ها این خط را اضافه میکنیم : [assembly: Xamarin.Forms.Dependency(typeof(XFCalc.UWP.Services.WelcomeMsg))] با توجه به کد بالا متوجه خواهید شد که Attribute موسوم به Dependency در زمارین فرم را به کلاس پروژه خود متصل نمودیم . به این ترتیب بین اینترفیس در پروژه مشترک و کلاس ما در هر سیستم عامل ارتباط برقرار میشود . حال به صورت مشابه همین کلاس را در اندروید نیز خواهیم ساخت به صورت زیر : [assembly: Xamarin.Forms.Dependency(typeof(XFCalc.Droid.Services.WelcomeMsg))] namespace XFCalc.Droid.Services { class WelcomeMsg : IWelcomeMsg { public string GetWelcomeMessage() { return "Welcome to our Android Xamarin App"; } } } حال در زمل صفحه اصلی برنامه در پروژه مشترک یک Label جهت نمایش پیام به کاربر ایجاد میکنیم <ContentPage.Content> <Grid> <Label VerticalOptions="Center" HorizontalOptions="Center" x:Name="LabelMsg"/> </Grid> </ContentPage.Content> حال در قسمت کد سی شارپ همین صفحه از طریق کد زیر پیام خود را مرتبط با سیستم عاملی که برنامه در آن در حال اجراست دریافت میکنیم و به کاربر نمایش میدهیم . LabelMsg.Text = DependencyService.Get<IWelcomeMsg>().GetWelcomeMessage(); در آموزش های بعدی با کاربرد های بسیار گسترده تری از این قابلیت آشنا خواهید شد و تعدادی کلاس هایی که پیش از این نوشته ام رو به اشتراک میگذارم .
  15. آموزش برنامه نویسی با Xamain.Forms قسمت سوم : ساخت اولین پروژه (ماشین حساب) / ادامه در بخش قبلی با مقدمات آموزش ساخت پروژه و تصحیح پروژه (در صورت لزوم) آشنا شدیم . در این قسمت به آموزش ساخت اولین پروژه با زمارین میپردازیم . در فایل ویوی اصلی خود ابتدا رابط کاربری برنامه را طراحی میکنیم . طراحی رابط کاربری به شدت شبیه به WPF, UWP میباشد . در پروژه اول با آبجکت های نام آشنای Button و Grid کار میکنیم که همانطور که میدانید Grid فضایی جهت نمایش سایر آبجکت ها درون خود را به شما میدهد . Button یا دکمه ها برای گرفتن ورودی کاربر و انجام دستورات مرتبط استفاده میشود . آبجکت دیگری که در این پروژه به آن جهت نمایش نتیجه نیازمندیم Label میباشد که جهت نمایش متن غیر قابل ویرایش (متون ثابت مانند توضیحات) استفاده میکنیم . ابتدا یک کد XAML بسیار ساده ایجاد مینمائیم . سپس در قسمت XAML.CS کد های مربوط به کلیک دکمه ها را مینویسیم . حال به کمک شبیه ساز ها یا استفاده از دیوایس فیزیکی برنامه را اجرا کنید خواهید دید که برنامه بدون هیچ مشکلی دستگاه یا شبیه ساز اجرا میشود. در پایین اسکرین شاتی از اجرای برنامه در اندروید و ویندوز مشاهده میکنید . همانطور که مشاهده میکنید هر دو برنامه کاملاً مشابه همدیگر البته با قدری تفاوت در جزئیات اجرا گردیدند که این تفاوت های جزئی مربوط به طراحی Native سیستم عامل میباشد و زمارین به صورت پیشفرض از استایل های پیشفرض استفاده میکند تا برنامه بیشتر شبیه به اپ های مرسوم در سیستم عامل شوند . کد های انتشار یافته در بالا نیز نیاز به توضیحات زیادی ندارد به جز اینکه در قسمت XAML از HorizontalTextAlignment و VerticalTextAlignment استفاده شده که بر خلاف اکثر زبان های رایج از ککلمات Start, Center و End استفاده شده . لازم به توضیح است که VerticalTextAlignment معین محل قرار گیری متن در جهت عمودی در صفحه (یا بهتر بگم آبجکت پدر) را تعیین میکند که استارت یعنی در نقطه شروع آبجکت پدر (بالای آن) قرار میگیرد ، یا سنتر در مرکز و End در انتها یا پایین آبجکت . همچنین HorizontalTextAlignment به طور مشابه همین کار را در جهت افق انجام میدهد و استارت آن به معنی سمت چپ آبجکت و End آن به معنای راست آبجکت میباشد . از دیگر موارد قابل ذکر این است که FontSize در زمارین به صورت هم عددی و هم به صورت Large , small , Medium و.... قابل استفاده است و هر دوی آن ها صحیح است ، جهت Bold کردن یا Italic کردن متن نیز میتوانید از FontAttributes استفاده نمائید که البته تنها به بولد و ایتالیک محدود است و گزینه هایی مانند SemiBold را شامل نمیشود ! دانلود سورس کد