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

 

이번 시간에는 DataBase 관련 첫번째 시간으로 SQLite 를 알아보도록 하겠습니다.

보통 서버와 연결하지 않고 로컬로만 어떤 데이터를 다룰 때는 SQLite 가 가장 편한 것 같습니다.

이번에 소개할건 PlugIn.SQLite 입니다. (Nuget 에서 받을수 있습니다.)

 

프로젝트를 열고 솔루션의 NutGet 패키지 관리로 들어갑니다.

PlugIn.SQLite 로 검색하면 아래처럼 하나가 나옵니다.

오른쪽에 모두 체크하고 설치를 클릭합니다.

확인을 하게되면

각각 프로젝트 별로 (UWP 제외) SQLite 폴더가 생성되고 내부에 코딩이 자동으로 들어가 있게됩니다.

각각 프로젝트에 맞게 namespace 등은 변경해 주어야합니다.

[ Android ]

코드 내용 (프로젝트에 맞게 변경이 완료된 내용입니다.)

using System.IO;
using SQLite;
using Xamarin.Forms;
using XamarinFormsStudy.Android;

[assembly: Dependency(typeof(SQLite_Android))]

namespace XamarinFormsStudy.Android
{
    public class SQLite_Android : ISQLite
    {
        public SQLite_Android() { }
        public SQLiteConnection GetConnection()
        {
            var sqliteFilename = "MySQLiteDB.db3";
            string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
            var path = Path.Combine(documentsPath, sqliteFilename);
            // Create the connection
            var conn = new SQLiteConnection(path);
            // Return the database connection
            return conn;
        }
    }
}

[ iOS ]

코드내용 (프로젝트에 맞게 변경이 완료된 내용입니다.)

using System;
using System.IO;
using SQLite;
using Xamarin.Forms;
using XamarinFormsStudy.iOS;

[assembly: Dependency(typeof(SQLite_iOS))]

namespace XamarinFormsStudy.iOS
{
    public class SQLite_iOS : ISQLite
    {

        public SQLite_iOS()
        {
        }

        public SQLiteConnection GetConnection()
        {
            var sqliteFilename = "MySQLiteDB.db3";
            string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal); // Documents folder
            string libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder
            var path = Path.Combine(libraryPath, sqliteFilename);
            // Create the connection
            var conn = new SQLiteConnection(path);
            // Return the database connection
            return conn;
        }
    }
}

[ UWP ]

UWP 는 참조는 추가 되나 관련 파일이 자동으로 추가되지 않습니다.

수동으로 추가해 주어야합니다.

이식가능 프로젝트에 보면 'SQLite-AppSample' 폴더에 readme.txt 파일이 있는데 여기에 UWP 에 넣어야할 코딩이 나와있습니다.

UWP 프로젝트에서 클래스를 추가하고 위 코딩을 넣습니다.

당연히 프로젝트에 맞에 수정을 해야합니다.

코드 내용 (프로젝트에 맞게 변경이 완료된 내용입니다.)

using System.IO;
using Windows.Storage;
using SQLite;
using Xamarin.Forms;
using XamarinFormsStudy.UWP;

[assembly: Dependency(typeof(SQLite_Uwp))]

namespace XamarinFormsStudy.UWP
{
    public class SQLite_Uwp : ISQLite
    {
        public SQLite_Uwp()
        {
        }

        public SQLiteConnection GetConnection()
        {
            var sqliteFilename = "MySQLiteDB.db3";
            string documentsPath = ApplicationData.Current.LocalFolder.Path;
            var path = Path.Combine(documentsPath, sqliteFilename);
            // Create the connection
            var conn = new SQLiteConnection(path);
            // Return the database connection
            return conn;
        }
    }
}

 

[ 이식가능 프로젝트(PCL) ]

이식가능에 추가된 SQLite 관련된 파일중 TodoItem 은 테스트할 데이터에 대한 테이블의 형태가 정의되어있습니다.

using SQLite;

namespace XamarinFormsStudy
{
    public class TodoItem
    {

        // 키 정보이며 하나씩 증가합니다.
        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }

        public string Text { get; set; }

        public bool Done { get; set; }

        public override string ToString()
        {
            return string.Format("Done : {0}, Text : {1}", Done, Text);
        }
    }
}

그리고 SQLiteSamplePage 에서는 CRUD 관련 코딩 예시가 나와있습니다.

또한 ContentPage 도 제공해 주어 바로 실행하여 확인도 가능합니다.

App.xaml 파일에서 아래 처럼 호출되도록 하고 실행해 보면

MainPage = new SQLiteSamplePage().GetSampleContentPage();

아래 와 같은 결과가 나옵니다.

데이터는 입력항목과 스위치 버튼의 true,false 값이 Add 하면 저장되고 Refresh 하게되면 저장된 값이 아래로 나열됩니다.

 

 

참고

https://www.youtube.com/watch?v=nrXmA-0NoOE&index=26&list=PLpbcUe4chE7-5t2mlamz6yB0qzAfO5Yln

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

 

 

블루투스 참고용 링크

https://github.com/aritchie/bluetoothle

 

ListView 는 데이터를 나열하여 표시해주는 컨트롤입니다.

더이상 설명은 필요 없을것 같으니 바로 시작하겠습니다.

신규 ContentPage 를 생성하여 ListViewPage.xaml 를 만듭니다.

ListViewPage.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.ListViewPage">
    <ListView x:Name="MainListView" HasUnevenRows="True">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout Orientation="Horizontal" Padding="10">
                        <Label Text="{Binding ID}"/>
                        <StackLayout VerticalOptions="Center">
                            <Label Text="{Binding Name}" Font="Large"/>
                            <Label Text="{Binding Age}" />
                            <Label Text="{Binding Dept}" Font="Bold" Opacity="0.6"/>
                            <Label Text="{Binding Desc}" Font="Small"/>
                        </StackLayout>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</ContentPage>

위 내용을 설명하자면 ListView.ItemTemplate 은 리스트뷰에 바인딩될 항목에 대해서 일정한 모양으로 바인딩 될수 있도록 해주는

템플릿을 정의하기 위한 것이라고 보면됩니다.

<DataTemplate> <ViewCell > 의 내부에 데이터가 바인딩될 구조를 미리 정의 하면 데이터가 그 구조에 맞게 바인딩됩니다.

디자인 코드를 보면 ID는 왼쪽 끝으로 위치하고 다른 항목들 (Name,Age등) 은 오른쪽에 위치시켜 아래로 쭉 나열하여 위치시킨 것을 알수 있습니다.

이제 ListViewPage.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 ListViewPage : ContentPage
    {
        public ListViewPage()
        {
            InitializeComponent();

            //MainListView.ItemsSource = new List<string> { "AA", "BB", "CC" };

            // 데이터들을 정의합니다.
            ListViewTestData data1 = new ListViewTestData() { ID = 1, Name = "user1", Age = 34, Dept = "Povice", Desc = "TestUser1" };
            ListViewTestData data2 = new ListViewTestData() { ID = 2, Name = "user2", Age = 31, Dept = "Povice", Desc = "TestUser2" };
            ListViewTestData data3 = new ListViewTestData() { ID = 3, Name = "user3", Age = 30, Dept = "Povice", Desc = "TestUser3" };
            ListViewTestData data4 = new ListViewTestData() { ID = 4, Name = "user4", Age = 40, Dept = "kjun", Desc = "TestUser4" };

            List<ListViewTestData> testData = new List<ListViewTestData>();
            testData.Add(data1);
            testData.Add(data2);
            testData.Add(data3);
            testData.Add(data4);

            // ListView 의 Source 에 적용하면 디자인 코드의 itemtemplate 에 바인딩될 항목을들 찾아 바인딩됩니다.
            MainListView.ItemsSource = testData;
        }
    }

    /// <summary>
    ///  ListView 에 바인딩될 데이터입니다.
    /// </summary>
    public class ListViewTestData
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public string Dept { get; set; }
        public string Desc { get; set; }
    }
}

 

결과는 아래와 같습니다.

 

LisView 는 디자인을 어떻게 하냐에 따라서 정말 달라보입니다.

Styling 하는 방법도 시간이 된다면 포스팅 할 예정입니다.

 

참고

http://blog.naver.com/goldrushing/220668652665

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

https://www.youtube.com/watch?v=N0e3fPisIw8&list=PLpbcUe4chE7-5t2mlamz6yB0qzAfO5Yln&index=9

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

'Xamarin' 카테고리의 다른 글

(Xamarin Forms) 7.SQLite - PlugIn.SQLite  (0) 2017.07.12
(Xamarin Forms) Bluetooth - 링크  (0) 2017.07.11
(Xamarin Forms) 6.ListView  (0) 2017.07.11
(Xamarin Forms) 5.Chart - OxyPlot (Line Chart)  (0) 2017.07.11
(Xamarin Forms) 5.Chart - OxyPlot  (0) 2017.07.10
(Xamarin Forms) 4.Image  (0) 2017.07.06

지난 포스팅에 이어 http://kjcoder.tistory.com/327

OxyPlot 차트로 라인 차트를 하나 그려보도록 하겠습니다.

차트의 x축은 시간이고 y 축은 숫자 값입니다.

또한 각 포인트에 라벨로 표시를 해주고 동그란 점으로 포인트를 찍을 예정입니다.

신규로 ContentPage 를 하나 만들어 OxyPlotLineChartPage.xaml 를 생성합니다.

xaml파일에는 아래 처럼 이전 포스팅과 동일하게 PlotView 컨트롤을 위치시킵니다.

<?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:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"
             x:Class="XamarinFormsStudy.OxyPlotLineChartPage">
        <Grid>
            <oxy:PlotView x:Name ="PlotChart"
                      VerticalOptions="Center"
                      HorizontalOptions="Center"/>
        </Grid>
</ContentPage>

OxyPlotLineChartPage.xaml.cs 파일에서 아래 처럼 코딩해 줍니다.

(설명은 주석에 있습니다.)

using OxyPlot;
using OxyPlot.Annotations;
using OxyPlot.Axes;
using OxyPlot.Series;
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 OxyPlotLineChartPage : ContentPage
    {
        public OxyPlotLineChartPage()
        {
            InitializeComponent();

            Random r = new Random();
            // 차트에 표현해줄 데이터 입니다.
            Dictionary<DateTime, double> data = new Dictionary<DateTime, double>();
            data.Add(new DateTime(2017, 7, 10, 09, 30, 00), r.NextDouble());
            data.Add(new DateTime(2017, 7, 10, 10, 30, 00), r.NextDouble());
            data.Add(new DateTime(2017, 7, 10, 11, 30, 00), r.NextDouble());
            data.Add(new DateTime(2017, 7, 10, 12, 30, 00), r.NextDouble());

            .........

            CreateBarChart(false,"OxyPlot Line Chart", data);
        }

        private void CreateBarChart(bool stacked, string title, Dictionary<DateTime, double> dataList)
        {
            // 차트에 바인딩될 데이터 Model 입니다.
            var model = new PlotModel
            {
                Title = title,
                PlotType = PlotType.XY,
            };

            // x축은 시간이 보이도록 설정합니다.
            model.Axes.Add(new DateTimeAxis
            {
                Title = "시간",
                Position = AxisPosition.Bottom,
                StringFormat = "HH:mm:ss"
            });

            // Y 축은 값입니다.
            model.Axes.Add(new LinearAxis
            {
                Title = "값",
                Position = AxisPosition.Left
            });

            // 각 포인트의 데이터를 model 에 add 합니다.
            // 여기서 PointAnnotation 는 각 포인트에 라벨을 표시하기 위함입니다.
            var Points = new List<DataPoint>();
            //int idx = 0;
            foreach (var i in dataList)
            {
                var pointAnnotation = new PointAnnotation();
                pointAnnotation.X = TimeSpanAxis.ToDouble(i.Key);
                pointAnnotation.Y = i.Value;
                pointAnnotation.TextVerticalAlignment = VerticalAlignment.Top;
                pointAnnotation.TextHorizontalAlignment = HorizontalAlignment.Center;
                pointAnnotation.Text = (i.Value).ToString("#.00");
                // 실제 데이터 값을 포인트에 add 합니다.
                Points.Add(new DataPoint(TimeSpanAxis.ToDouble(i.Key), i.Value));
                // 해당 포인트에 대한 라벨표시값도 추가합니다.
                model.Annotations.Add(pointAnnotation);
            }

            // Line 차트를 그리기 위한 라인시리즈를 정의합니다.
            var s = new LineSeries();

            // 각 포인트에 동그란 점으로 표시하게 합니다.
            s.MarkerType = MarkerType.Circle;
            // 정의한 포이트 데이터들을 라인시리즈의 소스로 적용합니다.
            s.ItemsSource = Points;
            // 차트에 적용할 model 에 추가합니다.
            model.Series.Add(s);

            // 위에서 정의한 model 을 차트에 적용합니다.
            PlotChart.Model = model;
        }
       
    }
}

PlotType 에는 XY, Cartesian, Polar 3가지가 있습니다.

XY 는 보통 저희가 많이 보는 x축과 y축을 가지는 차트입니다.

Cartesian직교 좌표로 1분면 부터 4분면 까지 있는 차트입니다.

Polar 는 극좌표로 3차원 그래프입니다.

위 코드 실행 결과는 아래와 같습니다.

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

차트 컨트롤은 데이터의 추이 및 통계데이터를 볼때 사용됩니다.

차트는 많은 컴포넌트들이 있으며 유료도 존재합니다.

제가 여기서 소개할것은 무료인 OxyPlot 차트 입니다.

oxyplot 는 자마린 뿐만 아니라 윈폼용, WPF 용도 있습니다.

제가 테스트해본 결과는 ios, android, uwp 모두 잘 동작합니다.

이번 포스팅에서는 간단하게 바(bar)차트를 하나 그려보겠습니다.

추후 차트쪽은 계속 포스팅이 될수도 있을것 같습니다.

 

1. 이식가능 프로젝트에 oxyplot 를 nuget 에서 설치합니다.

oxyplot 로 검색하면 OxyPlot.Xamarin.Forms 가 있습니다. 이걸 설치합니다.

'확인' 하고

 

설치완료.

 

2. Android , IOS, UWP 등의 각 프로젝트에도 Nuget 을 통해 OxyPlot.Xamarin.Forms 를 설치합니다.

Android

iOS

UWP

 

3. 각 장치에 따른 코딩 추가

이식 가능 프로젝틑 제외한 각 장치 프로젝트에서 OxyPlot 을 초기화하는 함수를 반드시 호출해 주어야합니다.

Android (MainActivity.cs)

        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;

            base.OnCreate(bundle);

            global::Xamarin.Forms.Forms.Init(this, bundle);
            OxyPlot.Xamarin.Forms.Platform.Android.PlotViewRenderer.Init();
            LoadApplication(new App());
        }

iOS (AppDelegate.cs)

        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            OxyPlot.Xamarin.Forms.Platform.iOS.PlotViewRenderer.Init();
            LoadApplication(new App());

            return base.FinishedLaunching(app, options);
        }

UWP (App.xaml)

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();

                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();
        }

이제 환경구성은 완료

 

4. 차트를 생성합니다.

Content Page 를 하나 만듭니다.  (OxyPlottPage.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:oxy="clr-namespace:OxyPlot.Xamarin.Forms;assembly=OxyPlot.Xamarin.Forms"
             x:Class="XamarinFormsStudy.OxyPlotPage">
        <Grid>
            <oxy:PlotView x:Name ="PlotChart"
                      VerticalOptions="Center"
                      HorizontalOptions="Center"/>
        </Grid>
</ContentPage>

차트에 데이터를 채웁니다.

using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
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 OxyPlotPage : ContentPage
    {
        public OxyPlotPage()
        {
            InitializeComponent();
            CreateBarChart(false,"OxyPlot BarChart");
        }

        private void CreateBarChart(bool stacked, string title)
        {
            var model = new PlotModel
            {
                Title = title,
                LegendPlacement = LegendPlacement.Outside,
                LegendPosition = LegendPosition.BottomCenter,
                LegendOrientation = LegendOrientation.Horizontal,
                LegendBorderThickness = 0
            };

            var s1 = new BarSeries { Title = "Series 1", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 };
            s1.Items.Add(new BarItem { Value = 25 });
            s1.Items.Add(new BarItem { Value = 137 });
            s1.Items.Add(new BarItem { Value = 18 });
            s1.Items.Add(new BarItem { Value = 40 });

            var s2 = new BarSeries { Title = "Series 2", IsStacked = stacked, StrokeColor = OxyColors.Black, StrokeThickness = 1 };
            s2.Items.Add(new BarItem { Value = 12 });
            s2.Items.Add(new BarItem { Value = 14 });
            s2.Items.Add(new BarItem { Value = 120 });
            s2.Items.Add(new BarItem { Value = 26 });

            var categoryAxis = new CategoryAxis { Position = CategoryAxisPosition() };
            categoryAxis.Labels.Add("Category A");
            categoryAxis.Labels.Add("Category B");
            categoryAxis.Labels.Add("Category C");
            categoryAxis.Labels.Add("Category D");
            var valueAxis = new LinearAxis { Position = ValueAxisPosition(), MinimumPadding = 0, MaximumPadding = 0.06, AbsoluteMinimum = 0 };
            model.Series.Add(s1);
            model.Series.Add(s2);
            model.Axes.Add(categoryAxis);
            model.Axes.Add(valueAxis);

            PlotChart.Model = model;
        }

        private AxisPosition CategoryAxisPosition()
        {
            if (typeof(BarSeries) == typeof(ColumnSeries))
            {
                return AxisPosition.Bottom;
            }

            return AxisPosition.Left;
        }

        private AxisPosition ValueAxisPosition()
        {
            if (typeof(BarSeries) == typeof(ColumnSeries))
            {
                return AxisPosition.Left;
            }

            return AxisPosition.Bottom;
        }
    }
}

App.xaml 에서 이제 위에서 만든 XplotPage.xaml 를 호출해 줘야겠죠

        public App()
        {
            InitializeComponent();

            MainPage = new XamarinFormsStudy.OxyPlotPage();
        }

결과

 

각각의 세부설명은 추후 포스팅에서 더 다루도록 하겠습니다.

 

참고

https://www.codeproject.com/Articles/1167724/Using-OxyPlot-with-Xamarin-Forms

http://docs.oxyplot.org/en/latest/getting-started/hello-xamarin-forms.html

https://github.com/oxyplot/oxyplot

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

Image 는 사진이나 그림파일을 보여주도록 하는 컨트롤입니다.

보통 Image 는 각각의 장치 프로젝트 별로 그림 파일이 존재해야하고

그에따라 코딩이 좀 변화가 있어야합니다.

예를들면 아래처럼 각 장치별로 위치가 다르기 때문에 처리가 필요합니다.

beachImage.Source =  Device.OnPlatform(
            iOS: ImageSource.FromFile("Images/waterfront.jpg"),
            Android:  ImageSource.FromFile("waterfront.jpg"),
            WinPhone: ImageSource.FromFile("Images/waterfront.png"));

하지만 저희는 이를 한곳으로 몰아놓고 사용하고 싶기때문에 그 방법을 공유하고자 합니다.

우선 이식가능 프로젝트에 원하는 이미지를 넣습니다.

전 위처럼 3가지 이미지를 넣었습니다.

그리고 각각 이미지를 선택하면 아래 속성에서 빌드 작업이 '내용' 으로 되어있는데 '포함 리소스' 로 변경합니다.

위 작업까지만 하면 코딩단에서는 아래처럼 코드하여 이미지를 각 장치에 상관없이 바인딩 할수 있습니다.

Image image1 = new Image() { Source = ImageSource.FromResource("XamarinFormsStudy.bottom.png") };

하지만 xaml 파일에서도 사용하기 위해서는 추가 작업이 필요합니다.

먼저 클래스를 하나 추가하여 아래처럼 코딩합니다.

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

namespace XamarinFormsStudy
{
    [ContentProperty("Source")]
    public class ImageResourceExtension : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null)
            {
                return null;
            }
           
            var imageSource = ImageSource.FromResource(Source);

            return imageSource;
        }
    }
}

위 내용은 xaml 파일에서 이미지를 가져와서 바인딩 하고자 할때 위 ProvideValue 메서드를 타도록 해줍니다.

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:local="clr-namespace:XamarinFormsStudy;assembly=XamarinFormsStudy"
             x:Class="XamarinFormsStudy.AbsoluteLayoutPage">
    <ContentPage.Content>
        <AbsoluteLayout Padding="15">
            <Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" Rotation="30" Source="{local:ImageResource XamarinFormsStudy.bottom.png}" />
            <Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" Rotation="60" Source="{local:ImageResource XamarinFormsStudy.middle.png}" />
            <Image AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5, 0, 100, 100" Source="{local:ImageResource XamarinFormsStudy.cover.png}" />
        </AbsoluteLayout>
    </ContentPage.Content>
</ContentPage>

>위 내용의 결과

안드로이드

IOS

 

UWP

 

참고

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

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

+ Recent posts