NGame

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

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

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

  • روز های برد

    44

تمامی ارسال های NGame

  1. با سلام. تا کنون با مفاهیمی همچون View , ViewModel , Model, Command و Binding و انواع آن آشنا شدیم . در این قسمت میخواهیم با Converter آشنا شویم . به عنوان مثال متغیر public bool IsBusy در ویو مدل را میخواهیم تبدیل به Visibility برای یک ProgressRing نماییم . به صورت مستقیم این کار ممکن نیست پس یا باید در ویو مدل متغیر دیگری با نوع Visibility در نظر بگیریم یا یک کانورتر بنویسیم و آنرا در زمل فراخوانی کنیم . در اینجا از هر دو روش استفاده خواهیم کرد. روش اول (تبدیل در داخل ویو مدل) : ابتدا متغیر IsBusy را به ویو مدل خود می افزائیم : private bool _isbusy; public bool IsBusy { get => _isbusy; set { _isbusy = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsBusy")); } } حالا یک متغیر از نوع Visibility نیازمندیم که آنرا نیز ایجاد میکنیم . private Visibility _loadindivis; public Visibility LoadingIndicatorVisibility { get => _loadindivis; set { _loadindivis = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("LoadingIndicatorVisibility")); } } حالا برای ایجاد ارتباط بین دو متغیر در بخش set متغیر IsBusy مقدار LoadingIndicatorVisibility را نیز ست میکنیم . public bool IsBusy { get => _isbusy; set { _isbusy = value; if (value) LoadingIndicatorVisibility = Visibility.Visible; else LoadingIndicatorVisibility = Visibility.Collapsed; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("IsBusy")); } } به این صورت حالا در هر جا که بخواهیم Visibility یک شیء را با تغییر IsBusy تغییر دهیم کافیست Visibility="{Binding LoadingIndicatorVisibility, Mode=OneWay}" را استفاده کنیم . اما در صورتیکه تعداد متغیر های نیازمند تبدیلمان زیاد شوند دائماً باید بر تعداد متغیر ها بیافزاییم در حالیکه به عنوان مثال همه آنها تعداد bool به Visibility هستند. در این موارد از یک Converter واحد برای همیشه استفاده خواهیم کرد. خوبی این روش هم علاوه بر سادگی این هست که در پروژه های آینده هم در صورت نیاز به این نوع کانورتر دیگر نیاز به نوشتن مجدد آن نخواهد بود هر چند که کار دشوار هم نیست ! روش دوم (استفاده از Converter یا مبدل در زمل): برای استفاده از این روش ابتدا متغیر های از نوع Visibility که پیش از این تعریف نمودیم را حذف میکنیم چون دیگر به آنها نیازی نداریم . سپس در روت پروژه یک پوشه جدید به نام Converters ایجاد میکنیم . در پوشه ایجاد شده یک کلاس جدید با نام BoolToVisibilityConverter ایجاد میکنیم و سپس آنرا از اینترفیس IValueConverter ارث بری میکنیم : class BoolToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } } این کلاس حال دارای دو تابع Convert و ConvertBack میباشد که در اینجا ما فقط با تابع Convert سر و کار داریم . در تابع کانورت Value را دریافت میکنیم و سپس (در صورت نیاز با کمک Parameter و Language) تبدیلات را انجام میدهیم. در این آموزش فقط با value کار میکنیم و باید این مورد را در نظر داشته باشید که مقدار parameter و language قابل Bind نیستند (از نوع DependencyProperty نیستند) جهت اطلاعات بیشتر در مورد این موضوع جستجو کنید . با توجه به نیازمان تابع کانورت را به صورت زیر تبدیل مینماییم : public object Convert(object value, Type targetType, object parameter, string language) { var val = System.Convert.ToBoolean(value); if (val) return Visibility.Visible; else return Visibility.Collapsed; } حال در زمل یک پراگرس رینگ جهت تست این مبدل اضافه میکنیم <Page.DataContext> <VM:MainViewVM/> </Page.DataContext> <Grid Background="{Binding ColorName}"> <Grid VerticalAlignment="Center" HorizontalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBox Grid.Row="0" Text="{Binding ColorName, Mode=TwoWay}" BorderThickness="2" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200"/> <Button Grid.Row="1" Content="About" Command="{Binding AboutCmd}" IsEnabled="{Binding AboutCmd.CanExecuteFunc, Mode=OneWay}" Margin="0,5" Width="120" HorizontalAlignment="Center"/> </Grid> <ProgressRing Visibility="{Binding IsBusy,Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}" IsActive="True" Width="100" Height="100"/> </Grid> بدون شک در بخش Visibility="{Binding IsBusy,Converter={StaticResource BoolToVisibilityConverter}}" به ارور بر میخوریم به این دلیل که ریسورس این کانورتر را به زمل اضافه نکرده ایم. پس در ریسورس های صفحه این مورد را اضافه میکنیم : <Page.Resources> <Converter:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/> </Page.Resources> حال در ویومدل جهت دیدن تغییرات این تغییرات را اعمال میکنیم . public MainViewVM() { AboutCmd = AppCommand.GetInstance(); AboutCmd.ExecuteFunc = ShowAbout; IsBusy = false; } حال در کلیک کلید About این تغییرات را اعمال کنید . private async void ShowAbout(object obj) { //await new MessageDialog("I am learning MVVM").ShowAsync(); IsBusy = true; await Task.Delay(5000); IsBusy = false; } حال با اجرای برنامه و زدن کلید about قادر به مشاهده پراگرس رینگ برای مدت 5 ثانیه خواهید بود.
  2. با سلام . حتماً همیشه در برنامه هایی که تا کنون نوشته اید با مشکل تغییر در رابط کاربری مواجه بوده اید. اینکه یک بخش از رابط کاربری را بخواهید حذف کنید تغییر دهید و.... آزار دهنده به نظر میرسد چون بعد از تغییر رابط کاربری اسامی اشیاء را باید به گونه ای تغییر دهید که در بک کد های شما نیز وجود دارد مثلا لیستی با نام Lst را در بک کد مقدار دهی نموده اید پس از تغییر رابط کاربری باید به یک لیست ویو حتما همین نام را بدهید . وای به روزی که اصلا نفهمید اون آبجکت چی بوده! و اصلا این قسمت کدتون داره چی کار میکنه. خب برای حل این مشکل یک روش کد نویسی وجود داره که شاید با نام MVVM یا MVC به گوشتون خورده باشه . اما MVVM مخفف چیه ؟ کلمه MVVM از سه بخش تشکیل شده : M : مدل (Model) V : ویو (View) و VM : ویو مدل (View Model) بخش مدل فقط شامل کلاس های ما میشه. به عنوان مثال من توی یک برنامه موسیقی یک کلاس دارم مربوط به آلبوم خواننده که شامل اسم خواننده ، سال انتشار آلبوم ، تعداد ترک های آلبوم ، ترانه سرایان ، تنظیم کنندگان ، آی دی آلبوم و.... میباشد که به این کلاس ها که در آینده باهاشون توی رابط کاربری سر و کار هم داریم میگیم مدل. بخش ویو : این بخش از همه آشنا تره همون رابط کاربری صفحه است که با Xaml به عنوان مثال توی UWP و WPF میسازیم . اما بخش View Model : این بخش ارتباط دهنده مدل ها و ویو ها به هم دیگه هست . این بخش تا حدودی شبیه همون بک کد های کثیف خودمونه ولی یه تفاوت هایی داره که بعداً متوجه میشیم . توی فرآیند اجرای یک برنامه اول ویو لود میشه -> بعد ویو مدل رو فراخونی میکنه و مقادیر رو ازش میگیره و با معجزه بایندینگ به نمایش در میاره -> ویو مدل هم که در صورت لزوم به مدل ها دسترسی داره . خب حالا برای تست یه پروژه میسازیم به اسم ColorMVVM که در اینجا من پروژه رو از نوع C# UWP میسازم . سپس توی سولوشن اکسپلورر دو تا Folder به اسم های View و ViewModel میسازم . ادامه مطلب رو توی پست بعدی مینویسم .
  3. c#

    پروژه های بانک رو من نمیدونم چطور ولی یه شرکتی همشون رو تو استور منتشر کرده به جز فک کنم بانک شهر . اگه کسی رو تو بانک شهر ، بانک سپه ، ملی ، آینده یا سینا دارید میتونید ازشون اطلاعات بگیرید . البته بانک های ایران معمولا تو سایر کشور های مجاور شعبه دارن اگه اونجا ثبت شده باشن شاید بتونید از اون طریق برای ساخت اکانت اقدام کنید . متاسفانه تو این زمینه تنها کسایی که میتونن کمک کنن خود بانک هست ، پشتیبانی مایکروسافت و پشتیبانی Norton البته اگه هنوز نورتن متصدی تائیدیه شرکت ها باشه . من فقط تو توسعه اپ اگه کمکی لازم داشته باشید میتونم کمک کنم .
  4. c#

    سلام باید حتما یه شرکت واقعی تائید شده تو خارج ایران باشه . من قبلاً یک ماه درگیرش بودم که بگیرم برای اپلیکیشن چارخونه وجود شرکت باید توسط Norton تائید بشه تا قابل استفاده باشه اکانت که ما هر چقد پیگیری کردیم از طریق ساپورت نورتن و مایکروسافت نتونستیم نتیجه ای بگیریم . آخر سر بعد یک ماه درخواست refund دادیم که با توجه به شرایط خاص ما فقط درخواست رو تائید کردن (چون اکانت تائید نشده بود) وگرنه ریفاند فقط تا 7 روز امکانش هست . برای چه شرکتی دنبال این اکانتی ؟
  5. با سلام. امیدوارم تا اینجای آموزش سخت نبوده باشه . در این قسمت با Command آشنا میشیم . کامند ها همون ایونت ها هستن که به جای اینکه توی کد بیهایند (فایل xaml.cs) بنویسیم توی مدل ویو مینویسین . ابتدا یک کلاس با نام AppCommand در روت پروژه بسازید و این کد را داخل ان کپی کنید . using System; using System.Windows.Input; public class AppCommand : ICommand { #pragma warning disable CS0067 // The event 'AppCommand.CanExecuteChanged' is never used public event EventHandler CanExecuteChanged; #pragma warning restore CS0067 // The event 'AppCommand.CanExecuteChanged' is never used public static AppCommand GetInstance() { return new AppCommand() { CanExecuteFunc = obj => true }; } public Predicate<object> CanExecuteFunc { get; set; } public Action<object> ExecuteFunc { get; set; } public bool CanExecute(object parameter) { return CanExecuteFunc(parameter); } public void Execute(object parameter) { ExecuteFunc(parameter); } } برای استفاده از این کلاس در صفحه MainView یک باتن اضافه میکنیم . کد نهایی صفحه به صورت زیر خواهد بود: <Page.DataContext> <VM:MainViewVM/> </Page.DataContext> <Grid Background="{Binding ColorName}"> <Grid VerticalAlignment="Center" HorizontalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBox Grid.Row="0" Text="{Binding ColorName, Mode=TwoWay}" BorderThickness="2" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200"/> <Button Grid.Row="1" Content="About" Command="{Binding AboutCmd}" Margin="0,5" Width="120" HorizontalAlignment="Center"/> </Grid> </Grid> خب حالا توی ویو مدل باید کامند رو تعریف کنیم public AppCommand AboutCmd { get; set; } نکته خیلی مهم : تمام پراپرتی ها و کامند ها و.... ای که قراره از طریق زمل بتونیم بایندشون کنیم باید حتما و حتما به صورت property تعریف شده باشن یعنیpublic type PropertyName{get;set;} در غیر اینصورت بایندینگ انجام نمیشه مثلا اگه نوشته باشید public type pname; حالا کانستراکتور مربوط به ویو مدل خودمون رو میسازم و کد های زیر را داخلش مینویسیم : public MainViewVM() { AboutCmd = AppCommand.GetInstance(); AboutCmd.ExecuteFunc = ShowAbout; } بدون کوچک ترین شکی به خاطر اینکه هنوزShowAbout را تعریف نکردیم ازش ارور میگیره . پس ماوس رو روی ارورش ببرید و از پیشنهادات ویژوال استدیو گزینه اول یعنی Generate method 'MainViewVM.ShowAbout' را انتخاب کنید . حال تابعی به صورت زیر برای شما ایجاد میشود. private void ShowAbout(object obj) { throw new NotImplementedException(); } تابع را به صورت زیر تغییر میدهیم . private async void ShowAbout(object obj) { await new MessageDialog("I am learning MVVM").ShowAsync(); } حال برنامه را اجرا کنید . پس از اجرا روی کلید about کلیک کنید خواهید دید که پیام شما نمایش داده خواهد شد .
  6. توی این قسمت باید ویومدلمون رو تکمیل کنیم و ویو رو بسازیم . خب ابتدا توی ویو مدل این پراپرتی ها رو ایجاد میکنیم : class MainViewVM : INotifyPropertyChanged { private string _colorname; public event PropertyChangedEventHandler PropertyChanged; public string ColorName { get => _colorname; set { _colorname = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ColorName")); } } } توی ویژوال استدیو 2015 به قبل اگه استفاده میکنید دستور get رو به این حالت تغییر بدید : get { return _colorname; } تا ارور برطرف بشه . در اینجا یک پراپرتی پابلیک جهت ارتباط با View و یک پراپرتی پرایوت جهت نگه داری مقادیر ورودی و خروجی این پراپرتی ایجاد کرده ایم . به این شکل که هر وقت بخواهیم مقدار ColorName رو بخوانیم ابتدا مقدار _colorname را دریافت میکنیم و سپس مقدار را بر میگردانیم و هنگام مقدار دهی ابتدا مقدار ورودی را در متغیر پرایوت ذخیره میکنیم و سپس ایونت PropertyChanged را فراخوانی میکنیم و در ورودی تابع نام متغیری که مقدارش تغییر کرده را وارد مینماییم . جهت اصولی تر شدن کار هم پیش از اینکه مقدار رو تغییر بدید و ایونت را فراخونی کنید میتونید اول چک کنید که مقدار value با مقدار _colorname متفاوت هست یا خیر و در صورت متفاوت بودن مقادیر تغییرات را ست کنید . خب ویو مدل ما تکمیل هست . حالا سراغ ویو میرویم . داخل ویو یک تکست باکس اضافه میکنیم . <TextBox Text="{Binding ColorName, Mode=TwoWay}" BorderThickness="2" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200"/> همانطور که مشاهده میکنید مقدار Text را با بایندینگ به ویو مدل و پراپرتی مورد نظرم مرتبط کردم اما Mode توی بایندینگ سه نوع مد داریم . One Time / One Way / Two Way حالت پیشفرض بایندینگ One Time هست. به این معنی که یک بار از پراپرتی مقدارش رو دریافت میکنه و دیگه تغییر نمیکنه . مثلاً اگه ColorName مقدار Red رو برگردونه همیشه مقدارش Red باقی میمونه (با اینکه مقدار Color Name توی ویو مدل تغییر میکنه توی ویو تغییر نمیکنه* حالت OneWay یعنی هر وقت توی ویو مدل مقدار تغییر کرد توی رابط کاربری تغییر کنه ولی مثلا من اگه دستی توی این تکست باکس چیزی بنویسم تغییر من باعث تغییر مقدار ColorName در ویو مدل نمیشه . حالت TwoWay دقیقاً همون حالت OneWay هست با این تفاوت که مثلا من اگه مقدار داخل تکست باکس رو تغییر بدم توی ویو مدل هم تغییر میکنه . (مثلاً از این طریق میتونید یک فرم ثبت نام ساده رو فقط با 3 یا 4 تا پراپرتی پابلک ساده بسازید . ) در اینجا من از حالت TwoWay استفاده کردم چون میخوام مقدار تغییر کنه . حالا به گرید اصلی صفحه بک گراند میدم . <Grid Background="{Binding ColorName}"> <TextBox Text="{Binding ColorName, Mode=TwoWay}" BorderThickness="2" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200"/> </Grid> خب برنامه ما به اتمام رسید . حالا به App.Xaml.Cs بروید و صفحه ابتدایی برنامه را تغییر دهید . در متد protected override void OnLaunched(LaunchActivatedEventArgs e) خط زیر را rootFrame.Navigate(typeof(MainPage), e.Arguments); به صورت زیر تغییر دهید : rootFrame.Navigate(typeof(MainView), e.Arguments); و حالا برنامه را اجرا کنید . پس از اجرای برنامه نام یک رنگ را به انگلیسی در تکست باکس وارد نمایید و محلی خارج از تکست باکس کلید کنید . رنگ پس زمینه برنامه به رنگ تایپ شده تغییر میکند . در صورتی که متن شما اسم یک رنگ نباشد رنگ پیش فرض ویندوز به پس زمینه اعمال میشود. تا به این قسمت فرا گرفتیم که چگونه یک ویو و ویو مدل را به هم ارتباط دهیم . تفاوت انواع بایندینگ را متوجه شدیم و با مفهوم INotifyPropertyChanged آشنا شدیم . در قسمت های بعدی قدری با موارد حرفه ای تر سر و کار خواهیم داشت سورس کد برنامه
  7. خب تا به اینجای کار فقط با یه سری مفاهیم اونم نه چندان ملموس آشنا شدیم یه پروژه هم ساختیم با دو تا پوشه . برای اینکه کارمون منظم تر باشه توی پوشه View یک Blank Page ایجاد میکنیم به نام MainView. به صورت دل به خواه نام گزاری های خودتون رو هدفمند کنید من برای فایل هایویو پسوند View برای فایل های ViewModel از پسوند VM استفاده میکنم و برای مدل ها هم از پسوند Model . هر صفحه (ویو) که میسازیم یک ViewModel هم باید براش بسازیم . البته توجه داشته باشید که آیه ای جهت ساخت ویو مدل نازل نشده! اگر پیجی مثل About میخواید بسازید کهبه بک کد نیاز نداره یا خیلی محدود هست بک کدش میتونید از این کار صرف نظر کنید ولی فراموش نکنید این کار رو فقط برای ویو هایی انجام بدید که بک کد ندارند. خب پس تو پوشه ViewModel یک کلاس با نام MainViewVM یا MainVM یا هر نام دلخواهی بسازید . من از نام استفاده میکنم . خب حالا نوبت به ارتباط دادن View به ViewModel میرسه . همونطور که کمی قبل تر اشاره کردم ویو مسئول فراخوانی ویو مدل هست . پس به کد های Xaml مربوط به MainView مراجعه میکنیم و این سه خط کد را زمل اضافه میکنیم : <Page.DataContext> <VM:MainViewVM/> </Page.DataContext> خب بعد از اضافه کردن این سه خط کد بدون شک ویژوال استدیو ارور میده بهتون چون VM رو اصلا تعریف نکردیم چی هست . برای تعریف خودکارش با موس روی VM:MainViewVM برید تا علامت چراغ زرد رنگ بیاد و Show Potential Fixes رو بزنید . سپس Add xmlns using:ColorMVVM.ViewModel رو انتخاب کنید و حالا ارور ویژوال استدیو بر طرف میشه و به ابتدای کد زمل شما این خط اضافه میشه . xmlns:VM="using:ColorMVVM.ViewModel" معمولا توی پروژه های بزرگ ممکنه ارور همچنان سر جاش بمونه یا ارور دیگه ای ظاهر بشه که با بیلد کردن پروژه مشکل حل میشه . خب حالا میریم به سراغ ViewModel . کلاس ویو مدل رو باز میکنیم و کلاسش رو از نوع INotifyPropertyChanged ارث بری میکنیم به این صورت : class MainViewVM : INotifyPropertyChanged { } از اونجایی که باز هم INotifyPropertyChanged رو نگفتیم کلاسش چیه بهتون ارور میده که با بردن موس روی کلمه و زدن Show Potential Fixes پیشنهاد using System.ComponentModel; رو به شما میده که انتخاب کنید تا به صورت خودکار رفرنسش به صفحه اضافه بشه . اما مجدداً ارور جدیدی به همین INotifyPropertyChanged داده میشه که مربوط به Implement Interface میشه . در نهایت کلاسی به شکل زیر خواهیم داشت : class MainViewVM : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; } اما INotifyPropertyChanged چیست ؟ همانطور که از نام این اینترفیس کاملاً پیداست تغییر یک Property رو با ما گزارش میده. این تغییرات رو از طریق ایونتی که ساختیم با نام PropertyChanged به ما گزارش میده . ما معمولا مستقیماً با این ایونت سر و کار نداریم . در صورت فراخوانی شدن این ایونت رابط کاربری به صورت خودکار تغییر را دریافت نموده و تغییر لازم را در رابط کاربری ایجاد میکنه (معجزه بایندینگ که گفته بودم) خب تا به این جای کار یک پروژه ساختیم پوشه های ViewModel و View رو ایجاد کردیم . یک ویو و یک ویو مدل ایجاد کردیم و ارتباط بین ویو و ویو مدل رو برقرار کردیم همچنین خاصیت INotifyPropertyChanged رو به ویو مدل خودمون دادیم تا در صورت ایجاد هر گونه تغییر توی مقادیر گزارشش رو در ویو بتونیم دریافت کنیم .
  8. سلام الان کدوم نسخه ویژوال استدیو رو نصب داری ؟ از ارور اسکرین شات بزار
  9. با سلام در این آموزش با مقدمات برنامه نویسی کراس پلتفرم (مالتی پلتفرم) با استفاده از Xamarin.Forms در خدمت شما هستم . فرض این آموزش بر این هست که شما برنامه نویسی به زبان سی شارپ (C# .Net) را از پیش فرا گرفته اید و آشنایی حداقلی با HTML یا XAML دارید . بنا به دلیل اینکه منابع موجود برای پرسش و پاسخ از Xamarin کمتر از منابع موجود برای Native پلتفرم ها میباشد ابتدا حتماً بر روی یکی از زبان های مبتنی بر سی شارپ تسلط داشته باشید . به دلیل شباهت بیشتر ترجیحاً یکی از این زبان ها / سیستم عامل ها را انتخاب کنید : UWP / WPF / Windows Phone Silverlight / Windows Runtime در این آموزش از Visual Studio 2017 و شبیه ساز اندروید مایکروسافت استفاده شده است . در قسمت اول آموزش به سراغ تنظیم امولاتور خواهیم رفت تا شبیه ساز دسترسی به اینترنت داشته باشد و پس آن به آموزش خواهیم پرداخت . امیدوارم که این آموزش مورد توجهتون قرار بگیره . » پیوند های مرتبط « آموزش نصب و راه اندازی زامارین با شبیه ساز مک آموزش تنظیم Visual Studio Emulator for Android جهت دسترسی به اینترنت (پست شماره #2 همین مطلب)
  10. مشکل حل شد . اومدم رو وی پی اس دیتابیس ساختم با ریموت بهش وصل شدم و خود انتیتی فرمورک رو مستقیم بهش وصل کردم حل شد
  11. سلام خسته نباشید . دوستان من چند وقته کار با Asp.Net MVC رو شروع کردم ولی به شدت با دیتابیس مشکل دارم به طوری که همه چی روی پی سی اوکی و بدون مشکل هست زمانی که رو هاست میره پروژه به هیچ عنوان به اسکیوال سرور کانکت نمیشه و تو این چند روز دست کم 150 تا ارور کاملا متفاوت رو شاهد بودم اگه میشه یه آموزش از ساخت یه دیتابیس خیلی مبتدی در همین حد که مثلا یه نام از کاربر بگیره ثبت کنه بزارید تو انجمن از ابتدا تا جایی که پروژه رو روی هاست یا VPS میزارید و کانکشن دیتابیس رو درست کنید . هر چی سرچ کردم و هر چی تست کردم حاصل فقط ارور جدید بود مرسی اه
  12. والا از من که اصلا اپل آی دی نخواست ! فیلتر شکن هم استفاده نکردم چه کردی که اپل ای دی خواسته ازت
  13. c#

    جواب کل سوالاتت تو سه خط کد : MPE.Source = Windows.Media.Core.MediaSource.CreateFromUri(new Uri("http://....", UriKind.RelativeOrAbsolute)); MPE.MediaPlayer.Play(); MPE.MediaPlayer.Pause(); //MPE = MediaPlayerElement
  14. استفاده از جیسون کار ساده ای هست . بستگی به سمت سرور داره اگه ASP باشه یه تابع برا اینکار داره به اسم Json اگر اشتباه نکنم . یادم نیست یک ساله تقریبا کار نکردم یادم رفته . توی نوگت های زمارین فرم هم یه نوگت هست NewthonSoft Json معمولا همون اولین نوگت میاد انقد پر کاربرده . اموزش کار باهاش هم یه سرچ کنی هست
  15. آموزش کار با 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 کردن نمایش کلید بازگشت باعث نمایش این کلید نخواهد شد . نکته : اگر صفحه ای کلید بازگشت از آن محو شود باعث از کار افتادن عملکرد کلید بازگشت دستگاه های اندروید و ویندوز فون نخواهد شد .
  16. هم از لحاظ امنیتی هم از لحاظ مواجه شدن با مشکلات اصلا کار درستی نیست که به صورت مستقیم با دیتابیس کار کنید . شما باید یک WebApi بنویسید که از طریق اون به سرور درخواست بدید سرور از روی دیتابیس اطلاعات مورد نظر رو برای شما به صورت JSON یا XML ارسال کنه . در گذشته XML خیلی کاربرد داشت ولی الان تقریباً همه JSON استفاده میکنن چون کوتاه تر هست و حجم اطلاعات ارسالی و دریافتی کمتره . پایگاه داده سمت سرور هم قاعدتاً Oracle یا SQL Server (ترجیحاً ورژن 2016) باشه نتیجه بهتری میگیرید .
  17. آموزش برنامه نویسی با 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>
  18. این راه اگه جواب نده راهش BackgroundMediaPlayer هستش . باید یک Windows Runtime Component بسازی که به اون مسج بزنی از فورگراند اون اجرا کنی . خواه ناخواه یک مقدار پیچیده هست ذاتاً روشش . در ضمن این روش که رامتین معرفی کرده برای بیلد 14393 به بعد فقط جواب میده البته مطمئن نیستم . تو داکیومنت مایکروسافت فک کنم نوشته بود 14393 میخواد
  19. آموزش برنامه نویسی با 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"/>
  20. ببخشید من یه مشکلی کلا با این Transport Controls دارم اونم اینکه یه بار یکی از کلیداش رو بزنی بعد چند دقیقه دیگه کلا کلید هاش از کار میافته اگه دوباره کلیدی نزده باشی . یکم سرچ کردم دیدم با AutoResetEvent و ManualResetEvent انگار باید حلش کرد ولی بازم نتونستم مشکل رو حل کنم . راه حلی داری براش ؟
  21. آموزش برنامه نویسی با 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 کرد بحثی هست که در قسمت بعدی آموزش بهش میرسیم .
  22. تشکر از پوریا بابت آموزش . یک سری نکات : اگر موقع ایجاد ماشین مجازی توی 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 هم اسم فایل برنامه رو باید بنویسید
  23. آموزش برنامه نویسی با 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(); در آموزش های بعدی با کاربرد های بسیار گسترده تری از این قابلیت آشنا خواهید شد و تعدادی کلاس هایی که پیش از این نوشته ام رو به اشتراک میگذارم .
  24. آموزش برنامه نویسی با 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 را شامل نمیشود ! دانلود سورس کد
  25. نصب آفلاین شبیه ساز اندروید 6 برای Visual Studio Emulator for Android با سلام . همانطور که میدانید در نسخه های جدید ویژوال استدیو (فکر میکنم ویژوال استدیو 2015 به بعد) یک شبیه ساز اندروید به این ابزار قدرت مند اضافه شده که به شما امکان تست برنامه ها را بدون نیاز به دیوایس فیزیکی اندروید میدهد . این شبیه ساز بسیار روان ، سبک و کم حجم بوده و بدون شک به شدت با ویژوال استدیو هماهنگی دارد . در صورتیکه از این شبیه ساز ها استفاده میکنید میدانید که میتوانید پروفایل های دیگری را نیز دانلود نمائید تا از شبیه ساز های اندروید های جدید تر برای تست برنامه های خود استفاده کنید . در اینجا لینک جدید ترین پروفایل را قرار میدهم تا بدون نیاز به دانلود بتوانید از امولاتور های آن استفاده نمائید . Android M (Marshmallow / 6.0 / API 23) لینک دانلود پروفایل پس از دانلود فایل msi را اجرا کرده و منتظر پایان نصب آن بمانید . پس از نصب پروفایل در کرتانا (استارت) عبارت Visual studio emulator for android را جستجو کنید و برنامه را اجرا کنید . حال از قسمت مشخص شده پکیج دانلودی خود را انتخاب کنید یعنی Marshmallow API 23 سپس از بین شبیه ساز های موجود هر یک که میخواهید به سلیقه خود انتخاب و نصب نمائید حال بدون نیاز به دانلود امولاتور شروع به نصب خواهد نمود. نکته : بهتر است از شبیه ساز های با سایز صفحه و رزولوشن پائین تر استفاده نمائید که هم سریع تر و روان تر اجرا شود و هم به صورت پیشفرض با سایز صفحه سیستم شما هماهنگ باشد و نیاز به تغییر زوم شبیه ساز نباشد این آموزش برای اولین بار و به صورت اختصاصی در اینجا منتشر میشود ، کپی برداری از این مطلب با ذکر منبع و نویسنده بلامانع است . باتشکر