Xamarin.Android 에서 

Adapter 생성자 부분의 : base() 에서 아래와 같이 에러가 발생되었다.

Unhandled Exception:

Java.Lang.ClassNotFoundException: md56301966bdf5adab103e6eb62103e8aa0.AlarmAdapter 발생

 

분명 다른 프로젝트에서도 이상없이 사용했던건데 에러가 나서 원인을 찾아봤다..

해결은 프로젝트 정리;;

프로젝트를 정리하고 재빌드 하니 위에러가 사라졌다..;;

 

결과는 아래와 같습니다.

시간은 millisecond 단위 입니다.


millisecond CPU Memory Disk
Count Android Xamarin Android Xamarin Android Xamarin
평균 249.5 147.5 102.2 27 7708.1 12753.7
1 240 137 97 24 8321 13701
2 227 143 109 27 8048 13430
3 257 148 85 26 7737 13564
4 281 161 184 62 7792 13614
5 234 153 94 31 7713 13284
6 270 149 89 17 7524 11229
7 253 185 92 21 7471 12094
8 252 125 102 28 7889 12344
9 250 133 89 16 7318 12031
10 231 141 81 18 7268 12246



결론,

Cpu, Memory 속도는 Xamarin 이 빠르고

Disk 는 Android 가 빠르다 입니다.

 

https://www.visualstudio.com/ko/app-center/?utm_source=VSSubscriptionsNewsNov2017&wt.mc_id=AID642788_EML_5311981&rr=http%3A%2F%2Fm.facebook.com%2F

여러장치에서 테스트가 가능하고 빌드및 배포가 가능하다고한다

조만간 시도해봐야겠다

https://www.mfractor.com/

자마린 개발을 편하게 해주는 Mac 용 툴인것 같은데 써보고 포스팅해봐야겠다

자꾸 잊어먹어서 글로 남겨놓는다.^^;

Grid 를 기본 제공 되는걸 쓰는게 좋겠지만 기능과 Styling 등을 하려면 시간이 많이 소요됩니다.

그렇기 때문에 좋은 컴포넌트가 있다면 쓰는걸 선호하는 편입니다.

Grid 쪽을 찾다보니 Syncfusion 이 눈에 들어왔습니다.

https://www.syncfusion.com/products/xamarin

SfDataGrid 만을 보고 들어왔는데 정말 많은 컨트롤들이 Xamarin 에서 사용가능하도록 되어있는걸 확인 할수 있었습니다.

여기 있는 컨트롤 가지고도 개발하기엔 충분해 보이네요

단 가격이 문제입니다. 그런데 다행히도

Free Community License 라고 해서

개인개발자이거나 연매출이 1백만달러 이하고 5명이하인 회사에는 무료로 사용가능하다고 합니다.

다음에 여기 컨트롤들을 좀 가져다가 써본걸 포스팅 해봐야겠네요

차트부터 우선 궁금합니다.

이제 본론으로 들어가서 SfDataGrid 를 살펴보겠습니다.

우선 사용하기 위해선 Nuget 에서 다운을 해야하는데요

NuGet.org 가 아닌 다른 곳에서 가져와야합니다.

솔루션용 NuGet 패키지 관리로 들어가서

상단의 패키지 소스 항목 옆의 톱니바퀴(설정)를 클릭합니다.

아래와 같은 창이 나오고 우측 상단에 + 을 누르고 추가된 패키지 소스 내용을 변경합니다.

이름은 아무거나 (예: syncfusion package)

소스는 http://nuget.syncfusion.com/nuget_xamarin/nuget/getsyncfusionpackages/xamarin/

으로 설정하고 업데이트 버튼을 한번 클릭해 주고 확인하고 나갑니다.

위 작업이 완료되면 패키지 소스에 내가 추가한 소스를 선택하고 sfdatagrid 로 검색하면 아래 처럼 검색이 됩니다.

솔루션용이라 우측에 각 프로젝트를 선택하도록 되어있는데 모두 선택하고 설치를 진행합니다.

확인...

무료라 고맙다. 동의함.

이제 각 프로젝트에 참조가 추가된걸 확인할수 있습니다.

아직 준비가 끝난게 아닙니다.

Android 는 기본적으로 수행이 가능하나

iOS, UWP 코딩에 초기화하는 내용을 넣어주어야합니다. (OxyPlot 차트 했을 때와 비슷)

iOS (AppDelegate.cs)

using System;
using System.Collections.Generic;
using System.Linq;

using Foundation;
using UIKit;

namespace XamarinFormsStudy.iOS
{
    // The UIApplicationDelegate for the application. This class is responsible for launching the
    // User Interface of the application, as well as listening (and optionally responding) to
    // application events from iOS.
    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        //
        // This method is invoked when the application has loaded and is ready to run. In this
        // method you should instantiate the window, load the UI into it and then make the window
        // visible.
        //
        // You have 17 seconds to return from this method, or iOS will terminate your application.
        //
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            OxyPlot.Xamarin.Forms.Platform.iOS.PlotViewRenderer.Init();
            Syncfusion.SfDataGrid.XForms.iOS.SfDataGridRenderer.Init();

            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }
    }
}

UWP (App.xaml.cs)

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace XamarinFormsStudy.UWP
{
    /// <summary>
    /// Provides application-specific behavior to supplement the default Application class.
    /// </summary>
    sealed partial class App : Application
    {
        /// <summary>
        /// Initializes the singleton application object.  This is the first line of authored code
        /// executed, and as such is the logical equivalent of main() or WinMain().
        /// </summary>
        public App()
        {
            this.InitializeComponent();
            this.Suspending += OnSuspending;
        }

        /// <summary>
        /// Invoked when the application is launched normally by the end user.  Other entry points
        /// will be used such as when the application is launched to open a specific file.
        /// </summary>
        /// <param name="e">Details about the launch request and process.</param>
        protected override void OnLaunched(LaunchActivatedEventArgs e)
        {

#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            Frame rootFrame = Window.Current.Content as Frame;

            // Do not repeat app initialization when the Window already has content,
            // just ensure that the window is active
            if (rootFrame == null)
            {
                // Create a Frame to act as the navigation context and navigate to the first page
                rootFrame = new Frame();

                rootFrame.NavigationFailed += OnNavigationFailed;

                Xamarin.Forms.Forms.Init(e);
                OxyPlot.Xamarin.Forms.Platform.UWP.PlotViewRenderer.Init();
                Syncfusion.SfDataGrid.XForms.UWP.SfDataGridRenderer.Init();

                if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
                {
                    //TODO: Load state from previously suspended application
                }

                // Place the frame in the current Window
                Window.Current.Content = rootFrame;
            }

            if (rootFrame.Content == null)
            {
                // When the navigation stack isn't restored navigate to the first page,
                // configuring the new page by passing required information as a navigation
                // parameter
                rootFrame.Navigate(typeof(MainPage), e.Arguments);
            }
            // Ensure the current window is active
            Window.Current.Activate();
        }

        /// <summary>
        /// Invoked when Navigation to a certain page fails
        /// </summary>
        /// <param name="sender">The Frame which failed navigation</param>
        /// <param name="e">Details about the navigation failure</param>
        void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
        }

        /// <summary>
        /// Invoked when application execution is being suspended.  Application state is saved
        /// without knowing whether the application will be terminated or resumed with the contents
        /// of memory still intact.
        /// </summary>
        /// <param name="sender">The source of the suspend request.</param>
        /// <param name="e">Details about the suspend request.</param>
        private void OnSuspending(object sender, SuspendingEventArgs e)
        {
            var deferral = e.SuspendingOperation.GetDeferral();
            //TODO: Save application state and stop any background activity
            deferral.Complete();
        }
    }
}

이제 준비 작업은 완료되었습니다.

 

신규 ContentPage 를 만들어 SfDataGridPage.xaml 를 생성합니다.

SfDataGridPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:syncfusion="clr-namespace:Syncfusion.SfDataGrid.XForms;assembly=Syncfusion.SfDataGrid.XForms"
             x:Class="XamarinFormsStudy.SfDataGridPage">
    <ContentPage.Content>
        <StackLayout>
            <syncfusion:SfDataGrid x:Name="dataGrid" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

SfDataGridPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XamarinFormsStudy
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class SfDataGridPage : ContentPage
    {
        private ObservableCollection<OrderInfo> orderInfo;

        public SfDataGridPage()
        {
            InitializeComponent();

            // 바인딩될 데이터를 추가합니다.
            orderInfo = new ObservableCollection<OrderInfo>();
            orderInfo.Add(new OrderInfo(1001, "Maria Anders", "Germany", "ALFKI", "Berlin"));
            orderInfo.Add(new OrderInfo(1002, "Ana Trujilo", "Mexico", "ANATR", "México D.F."));
            orderInfo.Add(new OrderInfo(1003, "Ant Fuller", "Mexico", "ANTON", "México D.F."));
            orderInfo.Add(new OrderInfo(1004, "Thomas Hardy", "UK", "AROUT", "London"));
            orderInfo.Add(new OrderInfo(1005, "Tim Adams", "Sweden", "BERGS", "Luleå"));
            orderInfo.Add(new OrderInfo(1006, "Hanna Moos", "Germany", "BLAUS", "Mannheim"));
            orderInfo.Add(new OrderInfo(1007, "Andrew Fuller", "France", "BLONP", "Strasbourg"));
            orderInfo.Add(new OrderInfo(1008, "Martin King", "Spain", "BOLID", "Madrid"));
            orderInfo.Add(new OrderInfo(1009, "Lenny Lin", "France", "BONAP", "Marseille"));
            orderInfo.Add(new OrderInfo(1010, "John Carter", "Canada", "BOTTM", "Tsawassen"));
            orderInfo.Add(new OrderInfo(1011, "Lauro King", "UK", "AROUT", "London"));
            orderInfo.Add(new OrderInfo(1012, "Anne Wilson", "Germany", "BLAUS", "Mannheim"));
            orderInfo.Add(new OrderInfo(1013, "Alfki Kyle", "France", "BLONP", "Strasbourg"));
            orderInfo.Add(new OrderInfo(1014, "Gina Irene", "UK", "AROUT", "London"));

            // 컬럼 Sorting 활성화 여부
            this.dataGrid.AllowSorting = true;

            // 더블 클릭시 이벤트
            this.dataGrid.GridDoubleTapped += DataGrid_GridDoubleTapped;

            // 데이터 로드시 이벤트
            this.dataGrid.GridLoaded += DataGrid_GridLoaded;

            // 편집여부
            this.dataGrid.AllowEditing = true;

            // 고정 컬럼/열
            this.dataGrid.FrozenRowsCount = 2;

            // 컬럼 이동 여부
            this.dataGrid.AllowDraggingColumn = true;

            // 데이터를 바인딩합니다.
            this.dataGrid.ItemsSource = orderInfo;

        }

        /// <summary>
        /// 데이터 로드시 이벤트입니다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGrid_GridLoaded(object sender, Syncfusion.SfDataGrid.XForms.GridLoadedEventArgs e)
        {
            ActivityIndicator indicator = new ActivityIndicator();
            indicator.IsRunning = true;
            indicator.IsVisible = true;
            indicator.BackgroundColor = Color.Gray;
            this.dataGrid.Children.Add(indicator);
            Task.Delay(2000).Wait();
            indicator.IsRunning = false;
            indicator.IsVisible = false;
        }

        /// <summary>
        /// 더블 클릭시 이벤트입니다.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGrid_GridDoubleTapped(object sender, Syncfusion.SfDataGrid.XForms.GridDoubleTappedEventsArgs e)
        {
            OrderInfo selectData = e.RowData as OrderInfo;
            DisplayAlert("Select Value", selectData.CustomerID, "OK");
        }

        /// <summary>
        /// 바인딩할 Test Class 입니다.
        /// </summary>
        class OrderInfo : INotifyPropertyChanged
        {
            private int orderID;
            private string customerID;
            private string customer;
            private string shipCity;
            private string shipCountry;

            public int OrderID
            {
                get { return orderID; }
                set { this.orderID = value; }
            }

            public string CustomerID
            {
                get { return customerID; }
                set { this.customerID = value; }
            }

            public string ShipCountry
            {
                get { return shipCountry; }
                set { this.shipCountry = value; }
            }

            public string Customer
            {
                get { return this.customer; }
                set { this.customer = value; }
            }

            public string ShipCity
            {
                get { return shipCity; }
                set { this.shipCity = value; }
            }

            public OrderInfo(int orderId, string customerId, string country, string customer, string shipCity)
            {
                this.OrderID = orderId;
                this.CustomerID = customerId;
                this.Customer = customer;
                this.ShipCountry = country;
                this.ShipCity = shipCity;
            }

            #region INotifyPropertyChanged implementation

            public event PropertyChangedEventHandler PropertyChanged;

            private void RaisePropertyChanged(String Name)
            {
                if (PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(Name));
            }

            #endregion
        }
    }
}

결과

 

위 사용한 기능 이외에도 다양한 기능들이 있습니다.

참고 링크로 확인해 주세요^^

 

참고

http://nuget.syncfusion.com/nuget_xamarin/nuget/getsyncfusionpackages/xamarin/

https://help.syncfusion.com/xamarin/sfdatagrid/getting-started

GitHub > https://github.com/kjundev/XamarinForms

이번시간에는 Picker 와 WebView 컨트롤을 알아보겠습니다.

(추가로 DisplayActionSheet 메서드 사용법도 알아볼께요)

 

Picker 는 윈폼으로 말하면 ComboBox 와 같은 형태로 여러 항목중에 하나를 선택할수 있는 컨트롤입니다.

https://developer.xamarin.com/api/type/Xamarin.Forms.Picker/

 

WebView 는 컨트롤 명에서도 유추할수 있듯이 웹페이지를 보는 컨트롤입니다.

WebView 에 url 을 넣어도 되지만 직접 html 코딩을 넣을수도 있습니다.

반드시 Android 에서 실행할때는 INTERNET 권한을 줘야합니다.

https://developer.xamarin.com/guides/xamarin-forms/user-interface/webview/

 

위 두 컨트롤의 예시 입니다.

WebPickerPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinFormsStudy.WebPickerPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="Picker"/>
            <Picker x:Name="picker" SelectedIndexChanged="picker_SelectedIndexChanged"/>
            <Button x:Name="button" Text="DisplayActionSheet" Clicked="button_Clicked"/>
            <Label Text="WebView"/>
            <WebView x:Name="webView" VerticalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

WebPickerPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XamarinFormsStudy
{
 [XamlCompilation(XamlCompilationOptions.Compile)]
 public partial class WebPickerPage : ContentPage
 {
  public WebPickerPage()
  {
   InitializeComponent ();

            this.Padding = new Thickness(10, Device.OnPlatform(40, 20, 20), 10, 5);

            // Picker 에 데이터를 Add 합니다.
            this.picker.Items.Add("Easy");
            this.picker.Items.Add("Normal");
            this.picker.Items.Add("Hard");


            this.webView.Source = new UrlWebViewSource { Url = "http://m.naver.com" };
        }

        private void picker_SelectedIndexChanged(object sender, EventArgs e)
        {
            // 선택한 항목을 팝업으로 띄워줍니다.
            string selectData = this.picker.Items[this.picker.SelectedIndex];
            DisplayAlert(selectData, "SelectValue", "OK");
        }

        private async void button_Clicked(object sender, EventArgs e)
        {
            // 선택 팝업이 뜨고 선택한 항목에 따라 버튼 색을 바꿔줍니다.
            string color = await DisplayActionSheet("선택하세요", "취소", "닫기", "BLUE", "YELLOW", "RED", "GREEN");
            switch (color)
            {
                case "BLUE": this.button.BackgroundColor = Color.Blue; break;
                case "YELLOW": this.button.BackgroundColor = Color.Yellow; break;
                case "RED": this.button.BackgroundColor = Color.Red; break;
                case "GREEN": this.button.BackgroundColor = Color.Green; break;
            }
        }
    }
}

결과

Normal 을 선택한 경우

 

추가로 DisplayActionSheet 함수는 목록 데이터를 팝업으로 보여주고 선택할 수 있게 합니다.

선택에 따른 처리도 가능합니다.

* 아래처럼 선택 항목들이 나열되고 선택하게되면 버튼 색이 선택한 색으로 변경됩니다.

 

GitHub > https://github.com/kjundev/XamarinForms

이번 포스팅에서는 진작에 다뤘어야하는 기본? 컨트롤을 소개하고자합니다.

말이 기본이지 이 기본 컨트롤이 가장 많이 쓰이게되죠.

 

1. Label

문자를 표현해주는 컨트롤로 보통 항목의 의미를 표시할때 사용됩니다.

<Label Text="label" />

https://developer.xamarin.com/api/type/Xamarin.Forms.Label/

https://developer.xamarin.com/guides/xamarin-forms/user-interface/text/label/

 

2. Button

말그대로 버튼입니다. 사용자가 터치나 클릭 했을때 이벤트를 통해 어떤 처리를 할수 있게합니다.

<Button Text="button" Clicked="Button_Clicked"/>

https://developer.xamarin.com/api/type/Xamarin.Forms.Button/

 

3. Entry

여기서 부터 좀 생소한데요 윈폼으로 생각하면 한줄만 입력 가능한 TextBox 입니다.

<Entry x:Name="entry" BackgroundColor="AliceBlue"/>

https://developer.xamarin.com/api/type/Xamarin.Forms.Entry/

https://developer.xamarin.com/guides/xamarin-forms/user-interface/text/entry/

 

4. Editer

익숙하면서도 생소한 단어같습니다.^^

Entry 랑 비슷한대 여러줄 입력이 가능한 컨트롤입니다.

<Editor x:Name="editor" VerticalOptions="FillAndExpand" BackgroundColor="AliceBlue" Text="Editor"/>

https://developer.xamarin.com/guides/xamarin-forms/user-interface/text/editor/

 

5. BoxView

이미지나 사용자정의 요소를 표시할떄 사용되며 기본 크기는 40*40 입니다.

<BoxView Color="Green" />

https://developer.xamarin.com/api/type/Xamarin.Forms.BoxView/

 

6. DatePicker

날짜를 선택할수 있도록 하는 컨트롤 입니다.

<DatePicker Format="D" />

https://developer.xamarin.com/api/type/Xamarin.Forms.DatePicker/

 

7. SearchBar

검색박스 컨트롤로 돋보기 모양의 아이콘과 하나로 되어있는 컨트롤입니다.

특정 문자열로 검색할때 쓰이는 것으로 검색시 이벤트를 통해 처리가 가능합니다.

<SearchBar x:Name="searchBar" SearchButtonPressed="searchBar_SearchButtonPressed" Text="SearchBar"/>

https://developer.xamarin.com/api/type/Xamarin.Forms.SearchBar/

 

8. ProgressBar

진행상태를 보여주는 컨트롤입니다.

<ProgressBar x:Name="progressBar"/>

https://developer.xamarin.com/api/type/Xamarin.Forms.ProgressBar/

 

9. ActivityIndicator

이 컨트롤도 진행 중임을 보여주는 컨트롤로 Progress 와는 다르게 진행률이 아닌 단순히 진행중인 것만을 나타냅니다.

<ActivityIndicator x:Name="activityIndicator" Color ="#80000000" IsRunning="True"/>

https://developer.xamarin.com/api/type/Xamarin.Forms.ActivityIndicator/

 

* 예시 코드

BaseControlPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="XamarinFormsStudy.BaseControlPage">
    <ContentPage.Content>
        <StackLayout>
            <Label Text="label" />
            <Label Text="ProgressBar" />
            <ProgressBar x:Name="progressBar"/>
            <Label Text="ActivityIndicator" />
            <ActivityIndicator x:Name="activityIndicator" Color ="#80000000" IsRunning="True"/>
            <SearchBar x:Name="searchBar" SearchButtonPressed="searchBar_SearchButtonPressed" Text="SearchBar"/>
            <BoxView Color="Green" />                
            <Label Text="DatePicker" />
            <DatePicker Format="D" />
            <Button Text="button" Clicked="Button_Clicked"/>
            <Entry x:Name="entry" BackgroundColor="AliceBlue" Text="Entry"/>
            <Editor x:Name="editor" VerticalOptions="FillAndExpand" BackgroundColor="AliceBlue" Text="Editor"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

BaseControlPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace XamarinFormsStudy
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class BaseControlPage : ContentPage
    {
        bool isActiveWindow = false;
        int buttonclick = 0;
        public BaseControlPage()
        {
            InitializeComponent();

            this.Padding = new Thickness(10, Device.OnPlatform(40, 20, 20), 10, 5);

            isActiveWindow = true;
            Device.StartTimer(TimeSpan.FromSeconds(0.1), TimerCallback);
        }

        private void Button_Clicked(object sender, EventArgs e)
        {
            // 버튼 클릭시 숫자를 증가하여 표시해줍니다.
            int i = buttonclick++;
            this.entry.Text = i.ToString();
            this.editor.Text += i.ToString() + Environment.NewLine;
        }
        bool TimerCallback()
        {
            progressBar.Progress += 0.01;
            return isActiveWindow || progressBar.Progress == 1;
        }

        private void searchBar_SearchButtonPressed(object sender, EventArgs e)
        {
            // 확인 팝업을 호출합니다.
            DisplayAlert("SearchBar",this.searchBar.Text + " Search...", "O", "X");
        }
    }
}

결과

UWP

Android

iOS

 

위에서 사용된 DisplayAlert 메서드는 자마린 폼에서 기본 제공해 주는것으로 확인 팝업을 호출합니다.

UWP

Android

iOS

 

참고

https://developer.xamarin.com/guides/xamarin-forms/user-interface/controls/views/

GitHub > https://github.com/knagjun/XamarinForms

SQLite 다루는 참고 동영상 링크

https://www.youtube.com/watch?v=t3w8HIdBFiA

 

+ Recent posts