4 Kasım 2016 Cuma

Xamarin.Forms Force Page Orientation and how to use Dependency simply


In Forms Project;

Dependency;



using Xamarin.Forms;

namespace MyProject
{
    public static class MBDGeneralMethods
    {
        static IMBDGeneralMethods _instance;
        public static IMBDGeneralMethods Instance {
            get{ 
                if (_instance == null) {
                    _instance = DependencyService.Get<IMBDGeneralMethods> ();
                }

                return _instance;
            }
        }
    }
}


DependencyInterface;


   using System;
   namespace MyProject
   {
      public interface IMBDGeneralMethods
      {
         void ForceLandscape();
         void ForcePortrait();
         void SetOrientionFree();
      }
   }




How to call it from any page;

In OnAppearing or in OnSizeAllocated or anywhere you want;


  
  protected override void OnSizeAllocated(double width, double height)
  {
     base.OnSizeAllocated(width, height); //must be called
     MBDGeneralMethods.Instance.ForceLandscape();
  }




In iOS Project; 

Info.plist;




AppDelegate.cs;


    [Export("application:supportedInterfaceOrientationsForWindow:")]
    public UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, IntPtr forWindow)
    {
       return UIInterfaceOrientationMask.AllButUpsideDown;
    }



Dependency;


using System;
using System.Threading;
using Foundation;
using YH.MB.iOS;
using UIKit;
using System.Drawing;
using UIKit;
using CoreGraphics;

[assembly: Xamarin.Forms.Dependency(typeof(MBDGeneralMethods))]
namespace MyProject.iOS
{
    public class MBDGeneralMethods : IMBDGeneralMethods
    {      
        public void ForceLandscape()
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.LandscapeRight), new NSString("orientation"));
        }

        public void ForcePortrait()
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Portrait), new NSString("orientation"));
        }

        public void SetOrientionFree()
        {
            UIDevice.CurrentDevice.SetValueForKey(new NSNumber((int)UIInterfaceOrientation.Unknown), new NSString("orientation"));
        }
    }
}



In Android Project;

Dependency;


using System;
using YH.MB.Droid;
using System.Net;
using Xamarin.Forms;
using Android.Graphics;
using Android.Content;
using System.IO;
using Android.App;
using Android;
using Android.Support.V4.Content;
using Android.Content.PM;
using Android.Support.V4.App;
using XLabs.Platform;
using Android.Views.InputMethods;
using System.Collections.Generic;
using System.Text;
using Android.Support.V4.Hardware.Fingerprint;
using Android.Hardware.Fingerprints;
using Android.Security.Keystore;
using Javax.Crypto;
using Java.Security;
using Android.Util;
using Java.Lang;

[assembly: Dependency(typeof(MBDGeneralMethods))]
namespace MyProject.Droid
{
    public class MBDGeneralMethods : IMBDGeneralMethods 
    {    
        public void ForceLandscape()
        {
            var activity = (Activity)Forms.Context;
            activity.RequestedOrientation = ScreenOrientation.Landscape;
        }

        public void ForcePortrait()
        {
            var activity = (Activity)Forms.Context;
            activity.RequestedOrientation = ScreenOrientation.Portrait;
        }

        public void SetOrientionFree()
        {
            var activity = (Activity)Forms.Context;
            activity.RequestedOrientation = ScreenOrientation.FullSensor;
        }
    }    
}


MainActivity.cs;

Add this line;
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)

like this;

    namespace MyProject.Droid{

    [Activity(Label = MBConsts.ApplicationName, Icon = "@drawable/icon",
        ScreenOrientation = Android.Content.PM.ScreenOrientation.Portrait,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : XFormsAppCompatApplicationDroid
    {

    ............



That's all.
Bye.
Kib :P

(Burada bir karikatür vardı ama telif yerim diye kaldırdım. Herkese dava açıyorlarmış karikatür paylaşılıyor diye. Karikatürün doğasına hiç uymuyor bence bu tavır :-/ Hayatın anlamını bulduktan hemen sonrası... amaan bu muymuş)

6 Ekim 2016 Perşembe

Some issues and solutions while converting your Xamarin.Forms Project into .Net Standard


Eğer Xamarin.Forms projenizi .Net Standard'a çevirmek istiyorsanız eminim aynı bizim gibi pek çok sorunla karşılaşırsınız. Eğer vakit bulursam karşılaştığımız tüm sorunları ve çözümleri yazacağım ancak hızlıca en çok sinir edeni paylaşmadan edemedim.  Zira bu konuyla ilgili ne hikmetse nette tek bir insan yazmış  ve yanlış yazmış. :@ MVP olacak bir de :P

Eğer projenizi .Net Standard'a çevirdikten, nuget packages'larınızı restore ettikten sonra Android projenizde

provides a compile-time reference assembly for mscorlib on MonoAndroid,Version=v6.0, but there is no run-time assembly compatible with win.

error CS1703: Multiple assemblies with equivalent identity have been imported
hatası alıyorsanız, pcl projenizdeki project.json dosyanızda;

"Microsoft.NETCore.Portable.Compatibility": "1.0.1"
 paketini şu şekilde güncelleyin;

"Microsoft.NETCore.Portable.Compatibility": {
      "version": "1.0.1",
      "type": "build"
    },

 şimdi de rebuild alın. Aaaa çalıştı. (Buna ulaşmak yarım günden fazla sürdü :( )


Bu arada örnek olması açısından project.json dosyalarımı paylaşmak istiyorum;

PCL project.json;

{
  "supports": {},
  "dependencies": {
    "AutoMapper": "5.0.0",
    "Acr.DeviceInfo": "4.0.2",
    "Acr.UserDialogs": "6.2.3",
    "CommonMark.NET": "0.14.0",
    "Microsoft.NETCore.Portable.Compatibility": {
      "version": "1.0.1",
      "type": "build"
    },
    "MonoCode.Forms": "1.0.0-pre05",
    "NETStandard.Library": "1.6.0",
    "Newtonsoft.Json": "9.0.1",
    "PCLStorage": "1.0.2",
    "Plugin.Permissions": "1.1.7",
    "System.ComponentModel": "4.0.1",
    "Toasts.Forms.Plugin": "3.1.0",
    "Xam.Plugin.DeviceInfo": "2.0.2",
    "Xam.Plugin.Geolocator": "4.0.0-beta4",
    "Xamarin.Forms": "2.3.2.127",
    "Xamarin.Insights": "1.12.3"
  },
  "frameworks": {
    "netstandard1.3": {
      "imports": "portable-net45+win8+wpa81"
    }
  }
}

Droid project.json;


{
  "dependencies": {
    "Acr.DeviceInfo": "4.0.2",
    "Acr.Support": "2.1.0",
    "Acr.UserDialogs": "6.2.3",
    "AndHUD": "1.2.0",
    "CommonMark.NET": "0.14.0",
    "ExifLib.PCL": "1.0.1",
    "MonoCode.Forms": "1.0.0-pre05",
    "Newtonsoft.Json": "9.0.1",
    "PCLStorage": "1.0.2",
    "Plugin.CurrentActivity": "1.0.1",
    "Plugin.Permissions": "1.1.7",
    "RestSharp": "105.2.3",
    "Toasts.Forms.Plugin": "3.1.0",
    "Xam.Plugin.DeviceInfo": "2.0.2",
    "Xam.Plugin.Geolocator": "4.0.0-beta4",
    "Xamarin.Android.Support.Animated.Vector.Drawable": "23.3.0",
    "Xamarin.Android.Support.Design": "23.3.0",
    "Xamarin.Android.Support.v4": "23.3.0",
    "Xamarin.Android.Support.v7.AppCompat": "23.3.0",
    "Xamarin.Android.Support.v7.CardView": "23.3.0",
    "Xamarin.Android.Support.v7.MediaRouter": "23.3.0",
    "Xamarin.Android.Support.v7.RecyclerView": "23.3.0",
    "Xamarin.Android.Support.Vector.Drawable": "23.3.0",
    "Xamarin.Forms": "2.3.2.127",
    "Xamarin.GooglePlayServices.Base": "29.0.0.2",
    "Xamarin.GooglePlayServices.Basement": "29.0.0.2",
    "Xamarin.GooglePlayServices.Gcm": "29.0.0.2",
    "Xamarin.GooglePlayServices.Measurement": "29.0.0.2",
    "Xamarin.Insights": "1.12.3"
  },
  "frameworks": {
    "MonoAndroid,Version=v7.0": {}
  },
  "runtimes": {
    "win": {}
  }
}

iOS project.json;


{
  "dependencies": {
    "Acr.DeviceInfo": "4.0.2",
    "Acr.Support": "2.1.0",
    "Acr.UserDialogs": "6.2.3",
    "BTProgressHUD": "1.2.0.3",
    "ExifLib.PCL": "1.0.1",
    "Microsoft.Bcl": "1.1.10",
    "Microsoft.Bcl.Build": "1.0.21",
    "Microsoft.Net.Http": "2.2.29",
    "MonoCode.Forms": "1.0.0-pre05",
    "PCLStorage": "1.0.2",
    "RestSharp": "105.2.3",
    "Rx-Main": "2.2.5",
    "Toasts.Forms.Plugin": "3.1.0",
    "WebP.Touch": "1.0.2",
    "Xam.Plugin.DeviceInfo": "2.0.2",
    "Xam.Plugin.Geolocator": "4.0.0-beta4",
    "Xamarin.Forms": "2.3.2.127",
    "Xamarin.Insights": "1.12.3"
  },
  "frameworks": {
    "Xamarin.iOS,Version=v1.0": {}
  },
  "runtimes": {
    "win": {}
  }
}

İyi çalışmalar cinlerim.

3 Mayıs 2016 Salı

You do not have sufficient privilege to access IIS web sites on your machine. (How dare you!)


Eğer Run as Administrator demezseniz Visual Studio şu şekıl çemkirebiliyor;

"The Web Application Project ..... is configured to use IIS.  Unable to access the IIS metabase. You do not have sufficient privilege to access IIS web sites on your machine."

Kes senini ben senin patronunum demek için, Run as administrator demeyi seçin. :P

Xamarin MessagingCenter'la ListView kullanarak picker sayfası oluşturma


Xamarin dünyasına girdiğimde Xamarin'e dair hiçbirşey bilmiyordum.. Azıcık C# bilgimle, deneme yanılma yöntemleriyle ve en çok da hocamın yardımlarıyla projeyi daha önce kullanmış olduğumuz javascript tabanlı platformdan hızlıca Xamarin'e geçirme çalışmalarına başladık. (çok şükür)

Pek çok yerde C#'ın event handler mantığını kullandık -ki ben bunu bile bu projede öğrendim.- . Daha sonra öğrendik ki meğer Xamarin'in MessagingCenter diye birşeyi varmış :) Bu MessagingCenter event handler ı sadeleştiren güzel bir yapı. Kısaca bir sayfadan başka bir sayfaya ya da sayfalara mesaj gönderiyoruz ve bu mesaja göre diğer sayfa(lar) aksiyon alıyor.

MessagingCenter örneklerini, uygulamalarını Xamarin'in sitesinde ve google amcada bulabiliriz. Örneğin;
https://developer.xamarin.com/guides/xamarin-forms/messaging-center/

Ben MessagingCenter'ı farklı bir şekilde nasıl kullandığımızı aktarmak istiyorumm. Projemizde kişi seçmemizi gerektiren, ya da listeden açıklamalı başka birşeyleri seçmemizi gerektiren pek çok bölüm var. Sürekli tekrarlı kod yazmaktansa bunu genel bir yapı haline getirip heryerde kullanalım diye düşündük. E peki nasıl? her kullandığımız yer için sayfanın aldığı parametreler de, listeden seçim yapıldığında tetiklecenecek metod da farklı. En pratik MessagingCenter kullanabiliriz diye düşündük :)

Öncelikle içinde ListView olan sade bir sayfa oluşturduk. Xaml'i;

  <ContentPage.Content>
    <ListView HasUnevenRows="true" x:Name="lvPicker" SeparatorColor="#e7e7e7" BackgroundColor="White" SeparatorVisibility="Default" VerticalOptions="FillAndExpand">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Spacing="4" Padding="10">
              <Label FontSize="Large" Text="{Binding Title}" />
              <Label FontSize="Small" TextColor="Gray" IsVisible="{Binding HasDescription}" Text="{Binding Description}" />
            </StackLayout>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>
    </ListView>
  </ContentPage.Content>


Kodu;


public partial class PagePicker : ContentPage
{
    string _sender;
    List<PickerItem_items;
    public PagePicker(string sender, List<PickerItem> items)
    {
        InitializeComponent();
        _sender = sender;
        _items = items;
        lvPicker.ItemsSource = _items;
        lvPicker.ItemTapped += LvPicker_ItemTapped;
        //Buraya kapatma demek olan çarpılı bir image koyduk. Siz de koyun :)
        ToolbarItems.Add(new ToolbarItem("Close""closeModal.png"async () =>
        {
            await Navigation.PopModalAsync();
        }, ToolbarItemOrder.Primary));
    }
 
    async void LvPicker_ItemTapped(object sender, ItemTappedEventArgs e)
    {
        MessagingCenter.Send(_sender, "PickerItemSelected", (PickerItem)lvPicker.SelectedItem);
        await Navigation.PopModalAsync();
    }
}

Basitçe modelimiz;

public class PickerItem
 {
  public string Title { getset; }
  public string Description { getset; }
  public bool HasDescription => !string.IsNullOrEmpty(Description);
  public string Value { getset; }
 }


Burada "LvPicker_ItemTapped" metodunda MessagingCenter'la Mesajımızı gönderdik. Peki nereye gönderdik? O da parametrik :)

Burada Subscribe öncesinde Unsubscribe yapıyor olmamızın amacı karışıklığı önlemek. MessagingCenter'la ilgili ufak bir püf nokta daha; eğer tek yerden Send edip birkaç yerden karşılamak istiyorsanız "sender"'larınızın farklı olmasına dikkat edin, yoksa sadece birini çalıştırıp diğerlerini takmaz.

Mesajı karşıladığımız genel metodumuz;

public async static Task Picker(this ContentPage page, string title, List<PickerItem> items, Action<stringPickerItem> action)
{
 var type = page.GetType();
 if (type == null)
 return;

 var sender = type.Name;
 MessagingCenter.Unsubscribe<string>(sender, "PickerItemSelected");
 MessagingCenter.Subscribe(sender, "PickerItemSelected", action);
 
 var navPage = new NavigationPage(new PagePicker(sender, items));
 navPage.Title = title ?? page.T("global.choose");
 navPage.BarBackgroundColor = Color.FromHex(MBConsts.TitleBgColor);
 navPage.BarTextColor = Color.FromHex(MBConsts.TitleTextColor);
 
 await page.Navigation.PushModalAsync(navPage);
}


Genel ListView sayfamız hazır. Artık istediğimiz yerden bu sayfayı çağırıp içine istediğimiz datayı gönderip istediğimiz aksiyonu aldırabiliriz :)

Örneğin;

try
{
    if (_accounts != null)
    {
        var items = _accounts.Select(a => new PickerItem
        {
            Description = a.HesapKodu,
            Title = a.HesapAdi,
            Value = a.HesapKodu
        }).ToList();
 
        await this.Picker(null, items, (sender, item) =>
         {
             //Picker'ımızdan bir item seçildiğinde alınacak aksiyonlar;
             lblAccountType.Text = item.Title;
             _accountId = item.Value;
         });
    }
}
catch (Exception ex)
{
    Log(ex);
}


Hoşçakalın cinlerim. Ben proje ile debelenmeye devam edeyim :)




7 Mart 2016 Pazartesi

Xamarin Android'te uygulamayı kapatmanın raconu


Application.Exit();

Ne de kolay, sade, anlaşılır, şirin, şık şükela bir komutt ^^ Uygulamamızı bir süre önce böyle kapatıyorduk. Meğerse "Force Close" işlevi görüyormuş :) Yani zoririymiş;

(Burada bir karikatür vardı ama telif yerim diye kaldırdım. Herkese dava açıyorlarmış karikatür paylaşılıyor diye. Karikatürün doğasına hiç uymuyor bence bu tavır :-/ Elzemin ne olduğunu biliyorum. Ne? Zoriri)

Peki zoriri olunca ne olur ki? Daha doğrusu ne olmaz ki? Meğer Application.Exit(); komutceğizimiz uygulamayı tamamen öldürdüğü için notification gitmesini bile engelleyecek kadar cüretkârmış. Eee ne olcak o kadar notification israf değil mi? Elbette ki öyle. O haldee Application.Exit(); yapmayıp

((Activity)Forms.Context).Finish();

yaparsak sorunumuz çözülüyor.

Kolay çözülen sorunları severim.. <3


24 Şubat 2016 Çarşamba

"How to create local certificate" ve local iis'le proje geliştirirken bunu kullanmak :)


Sayın Cinaliler ve cincimeler.

Vaadimi tutuup local sertifika nasıl oluşturulur bunun yöntemini açıklama blog girdime hepiniz hoşgeldiniz. Lafı çok uzatmayacağım. Başlayalım :)

Https li site yapmak istedik. Benim için bu konu bir muamma idi. Ancak alışveriş sitelerinde olması gerekiyordu. Tabi öncesinde test etsek iyiydi. Eldi, mahkumdu, ne yapsaktı, sorsaktı. Sordum. Uğraştı.

Yani bunu yapmak için bayağı uğraştık sertifika ssl vs konularına yabancılığımız yüzünden. Araştırma aşamasında birr dolu site dolaştık. En sonunda aradığımızı bulduk. Neden? Çünkü vazgeçmemiştik. (fon müziği çalar)
(Burada bir karikatür vardı ama telif yerim diye kaldırdım. Herkese dava açıyorlarmış karikatür paylaşılıyor diye. Karikatürün doğasına hiç uymuyor bence bu tavır :-/ Enişten değiş Einstein Einstein Yine de insan gurur duyuyor. )
Söz konusu olan site şu;

http://www.mikeobrien.net/blog/creating-self-signed-wildcard/

Bu sitede adım adım zaten anlatılmış ben özetle üzerinden geçeceğim.

Windows 10 ceğizimde "C:\Program Files (x86)\Windows Kits\10\bin\x64" dizininde bir adet makecert.exe diye yardımcı programcık vaar. Bu yardımcı programcığı emellerimize alet ederek amacımıza ulaşacağız. Eğer sizde böyle bir yardımcı programcık yoksa şuradan edinebilirsiniz;

https://msdn.microsoft.com/library/windows/desktop/aa386968.aspx

Ardından cmd'mizi "Run as Administrator" ile açıp aşağıdaki komuttan kırmızıları kendimize göre revize edip çalıştıralım.

"C:\Program Files (x86)\Windows Kits\10\bin\x64\makecert.exe" -n "CN=My Company Development Root CA,O=My Company,OU=Development,L=Wallkill,S=NY,C=US" -pe -ss Root -sr LocalMachine -sky exchange -m 120 -a sha256 -len 2048 -r

Ardından da şunu aynı şekilde kırmızı yerleri revize ederek çalıştıralım;
"C:\Program Files (x86)\Windows Kits\10\bin\x64\makecert.exe" -n "CN=*.dev.somesite.net" -pe -ss My -sr LocalMachine -sky exchange -m 120 -in "My Company Development Root CA" -is Root -ir LocalMachine -a sha256 -eku 1.3.6.1.5.5.7.3.1
Örnek olarak ben şöyle yaptım;
"C:\Program Files (x86)\Windows Kits\10\bin\x64\makecert.exe" -n "CN=Localhost,O=Localhost,OU=Development,L=Mono,S=NY,C=US" -pe -ss Root -sr LocalMachine -sky exchange -m 120 -a sha256 -len 2048 -r
"C:\Program Files (x86)\Windows Kits\10\bin\x64\makecert.exe" -n "CN=*.local.com" -pe -ss My -sr LocalMachine -sky exchange -m 120 -in "Localhost" -is Root -ir LocalMachine -a sha256 -eku 1.3.6.1.5.5.7.3.1 

---------------------------------


ÖNEMLİ NOT: Bu şekıl kullanımdan kaldırılmış. (makecert.exe Deprecated ) . Bunun yerine Microsoft Powershell'de çalıştırabileceğimiz "New-SelfSignedCertificate" komutunu getirmiş.
Ancak makecert.exe'yi bir yerlerden indirip vs kullanmaya devam edenler mutlaka olacaktır ondan çözümünü kaldırmıyorum. 

Yeni yolu da paylaşmadan edemeyeceğim;

Adım adım;

# 1. Bu adımda sertifikayı oluşturuyoruz.
$certItem = New-SelfSignedCertificate -DnsName *.local.com -CertStoreLocation cert:\LocalMachine\My -KeyExportPolicy Exportable

# 2. Oluşturduğumuz sertifikayı export / import işleminde kullanacağımız şifremizi üretiyoruz.
$certPass = ConvertTo-SecureString -String "P@assw0rd" -Force -AsPlainText

# 3. Sertifikayı Export edeceğimiz klasörü oluşturuyoruz.
New-Item "C:\Certs" -Type Directory -Force

# 4. Sertifikayı C:\Certs\local.com.pfx yoluna export ediyoruz. 
$certFile = Export-PfxCertificate -Cert "cert:\LocalMachine\My\$($certItem.Thumbprint)" -Password $certPass -FilePath C:\Certs\local.com.pfx

# 5. Export ettiğimiz sertifikayı Trusted Root'a ekliyoruz.
Import-PfxCertificate –FilePath "$($certFile.FullName)" cert:\localMachine\Root -Password $certPass


PowerShell'i Administrator olarak (Sağ tuş yönetici olarak çalıştır - Run as Administrator) çalıştırıp yukarıdaki adımları tek tek yapıştırıp çalıştırıyoruz.


-----------------------------------


Daha sonra iis'te bu sertifikamızı seçebiliyor olacağız;
Şu şekıl;



Bunu bana öğrettiği için uzmanıma sonsuz saygılar, hörmetler.

Eyvallah.


trip.. trip..

:p