軟體開發(軟件開發)

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

室內設計、裝潢、窗簾報價估算軟體

網智數位主要提供套裝及客製化的軟體系統解決方案,針對室內設計師、木工、裝潢業產業,量身訂做客製化的軟體,達成客製化、智慧化及網路化的商用軟體。

商用軟體-客製化設計

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

IOT 物聯網-系統開發

根據客戶實際狀況,結合雲端與載具進行客製化物聯網IOT導入與軟體開發

雲端VPS虛擬主機租用

我們的雲端VPS虛擬主機是採用雲端(虛擬化)技術所開發之全新雲端伺服器服務,可以選擇多種作業系統(Windows、Linux等),客戶可載入自訂的應用環境,執行自己所要提供的網路服務,我們的雲端服務可為您的網站提供最完美的解決方案。

ERP軟體客製化導入

ERP軟體客製化導入,室內設計、營造業、裝潢、木作工程、系統櫃工程、會計系統,全面提升公司管理營運效率。

搜尋引擎最佳化SEO

搜尋引擎最佳化(SEO)不僅能提高網站在搜尋結果的排名,更能帶來大量對我們產品或服務真正有需求的訪客。SEO 最棒的特質之一就是不像廣告一樣亂槍打鳥而導致用戶的反感,反而更能提升點閱率跟成交率喔。

服務宗旨

網智數位主要提供套裝及客製化的軟體系統解決方案,專為客戶量身訂做客製化的軟體,達成客製化、智慧化及網路化的管理功能。

我們的成立宗旨就是要以最猛的IT技術讓這個世界更Smart,在我們貫徹我們裡想的同時,我們希望可以把我們所開發的系統帶給台灣的中小企業,除了要推薦好的東西之外,我們也希望做點改變,所以我們的第一目標就是要使用最好用的系統再加上您寶貴的創意,不僅僅可以節省你大量的荷包,還可以有一個像樣的網站。我們可以幫你做的有

企業管理
  • 策略管理
  • 目標管理
  • 行銷管理
  • 財會管理
  • ERP導入
  • 企業流程自訂
資訊管理
  • 網站架設
  • 虛擬化/雲端架設
  • 主機代管
  • 私有雲建制與導入
軟體開發
  • UML設計
  • 版本控管
  • 企業軟體開發
  • APP開發
  • 網頁設計
資訊安全
  • 網頁弱點掃描
  • 主機弱點掃描
  • 木馬檢測
  • 資安鑑識
  • 設計網路架構
  • 資安監控
行銷
  • 關鍵字SEO
  • 社群網路行銷
  • 部落格行銷
  • FaceBook 粉絲團
其他
  • 協助企業申請Google Email
好玩工具開發

講出你的創意吧!沒有甚麼是資訊辦不到的

顯示具有 UWP 標籤的文章。 顯示所有文章
顯示具有 UWP 標籤的文章。 顯示所有文章

2018年7月25日 星期三

Xamarin 跨平台程式開發-訊息傳遞 - 軟體開發 教學

   在 Xamarin 開發 IOS、Android、UWP APP時,常常會遇到訊息接受與訊息傳遞,那麼這邊我想簡單示範如何在 Xamarin 實作一個訂閱訊息程式開發技巧。

Android 執行結果畫面
螢幕快照 2018-07-25 下午10.27.43螢幕快照 2018-07-25 下午10.28.49螢幕快照 2018-07-25 下午10.29.10


   Xamarin 透過 MessagingCenter 這個靜態類別來支援訂閱/通知訊息,這個類別主要需要知道三個 Methods ,分別為 Subscribe<TSender, TArgs> 與 Send<TSender, TArgs>、Unsubscribe<TSender, TArgs>。
Subscribe<TSender, TArgs> 方法用來訂閱訊息,當有訊息接受到時,可以通知使用者,例如出現對話訊息、畫面顯示訊息。
Send<TSender, TArgs> 方法用來通知訊息,已告知那些訂閱訊息者。
Unsubscribe<TSender, TArgs> 原先進行訂閱訊息接受,現在進行取消訂閱,後續如果有訊息通知,都不進行接受訊息。


程式範例示範
image

public class MainPageViewModel
    {
        public ObservableCollection<string> Greetings { get; set; }


        public MainPageViewModel ()
         {
            Greetings = new ObservableCollection<string> ();


           MessagingCenter.Subscribe<MainPage> (this, "哈嘍", (sender) => {
                Greetings.Add("哈嘍");
             });


            MessagingCenter.Subscribe<MainPage, string> (this, "哈嘍", (sender, arg) => {
                Greetings.Add("哈嘍 " + arg);
            });

        }
    }

在上面程式範例 宣告 一個 MainPageViewModel Class,這個作為 ViewModel 用途,在建構式裡實作訂閱服務,這個機制可以減少程式物件耦合度。


下面這行程式碼,主要是用於實作一個名叫 “哈嘍”的訂閱服務  MessagingCenter.Subscribe<MainPage> (this, "哈嘍", (sender) => {  Greetings.Add("哈嘍"); });





在底下的主程式 MainPage ,實作訂閱通知服務,主要程式邏輯,我透過註解程式說明

public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();


            //這邊我綁定一個ViewModel
            BindingContext = new MainPageViewModel();


            //宣告一個按鈕物件,當點選按鈕時,觸發一個發送訊息
            var button1 = new Button { Text = "Say 哈嘍" };
            button1.Clicked += (sender, e) =>
            {
                MessagingCenter.Send<MainPage>(this, "哈嘍");
            };


            //宣告一個按鈕物件,當點選按鈕時,觸發一個發送訊息,並傳遞內容參數,傳遞的內容是 Allen 

            var button2 = new Button { Text = "Say Hi to Allen" };
            button2.Clicked += (sender, e) =>
            {
                MessagingCenter.Send<MainPage, string>(this, "哈嘍", "Allen");
            };


            //宣告一個按鈕物件,當點選按鈕時,觸發一個取消訂閱服務,並取消對話視窗訊息!
            var button3 = new Button { Text = "取消訂閱服務,並取消對話視窗訊息!" };
            button3.Clicked += (sender, e) =>
            {
                MessagingCenter.Unsubscribe<MainPage, string>(this, "哈嘍");
                 DisplayAlert("取消訂閱服務",
                    "This page has stopped listening, so no more alerts; however the ViewModel is still receiving messages.",
                    "OK");
             };


            //訂閱服務(背後的ViewModel還是仍然保持本身實作的訂閱服務),並出現對話視窗訊息
            MessagingCenter.Subscribe<MainPage, string>(this, "哈嘍", (sender, arg) =>
            {
                DisplayAlert("訊息已接受", "參數訊息 為 " + arg, "OK");
            });

            //綁定接受到的訂閱訊息
            var listView = new ListView();
             listView.SetBinding(ListView.ItemsSourceProperty, "Greetings");

            //放置物件內容
            Content = new StackLayout
             {
                Padding = new Thickness(0, 20, 0, 0),
                Children = { button1, button2, button3, listView }
            };
        }




在 iPhone X 執行畫面如下
螢幕快照 2018-07-25 下午10.20.29螢幕快照 2018-07-25 下午10.20.46






網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
公司電話:02-55991310
公司地址(業務營運處):台北市中山區錦州街 25 號 5 樓
skype: netqna
line:netqna
微信:netqna
黃先生 Allen
my_qrcode_1519621481105

軟體派遣人力、專案軟體開發

軟體派遣人力
網智數位-軟體開發擴大合作團隊,現在可以提供企業人力駐點服務、提供 .Net 和 Java 技術入力駐點服務,我們的人力可以駐點於客戶處,與客戶技術團隊共同進行專案開發,並於專案結束後技術移轉並交接給客戶。       







專案軟體開發
我們更專注于解決客戶的需求,利用專業的資訊IT技能,協助客戶量身定做軟體開發、專案承接。
我們已開發過 圖控軟體、各產業ERP系統、POS系統、Arduino開發、簽核系統、進銷存軟體、電子發票系統、VR軟體。
橫跨產業:窗簾業、拉門、衛浴、地板、貿易業、醫療業、電子業、馬達知名廠商、汽車維修業。



 








網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
公司電話:02-55991310
公司地址(業務營運處):台北市中山區錦州街 25 號 5 樓
skype: netqna
line:netqna
微信:netqna
黃先生 Allen

my_qrcode_1519621481105

2017年9月5日 星期二

在非同步作業時,如何取消非同步任務(軟體開發、程式設計、軟件開發)

      在之前我寫過一篇關於用 Task 類別來撰寫非同步化作業(使用 Task 自行控制非同步任務作業),來利用多CPU、多核心處理器的優勢,這樣可以避免某些邏輯需要較長的時間去執行,而造成主界面程式停頓卡卡,讓使用者誤以為當機、或程式有問題,所以透過.Net 的 Task 任務,可以讓系統自行的調度限制可以用的執行緒(Thread)。

   既然有了 Task 任務類別的支援,可以讓我們輕易的撰寫多工、非同步作業的程式,讓長時間執行的程式透過另外一個執行緒(Thread)在背後執行,例如我常幫工廠或企業寫物料需求計算(MRP、MPS計算)、業績獎金計算、APS先進排程規劃,這些都是需要執行讀取大量的系統資料來進行運算,這就可以充分利用 ThradTask的技術再背後另外一個執行緒去執行,使用者,在前端主畫面還可以繼續執行其他作業,而不用只能等待程式執行完畢。
    不過我們也常常遇到常時間執行的程式,我們可以提供一個按鈕讓使用者去選擇【取消】背後執行的任務,那麼這篇技術文章我就是想講解,如何在.Net 平台取消非同步化作業的任務 ,.net 平台裡有個類別專門跟 Task 、Task<TResult> 類別搭配使用,使得完成取消非同步任務作業的執行,這個類別就是 CancellationTokenSource 類別

我在這邊一樣透過 Step By Step 來建立一個範例程式,來說明整個程式的撰寫技巧…


1.這邊我簡單為了好示範,我建立一個 Windows Form 視窗專案,命名為 CancellationTokenSource_Demo,如下圖:

繪圖

2.在 Form1 表單,我設計了一下畫面
繪圖2
在Form1表單,我為了示範,所以放置了2個 Label (分別顯示 輸入一個正整數、運算結果顯示),2個 Button 按鈕(分別為 進行運算、取消非同步任務),還有一個 ProgressBar (作用於非同步任務執行時,可以顯示進度條狀態)。

3.在 Form1.cs 的後端程式,是最重要的,我把程式標註註解,這樣大家就可以容易理解了。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }


    /// <summary>
    /// 宣告一個 用於支援取消非同步任務的變數
    /// </summary>
    private CancellationTokenSource cts = null;


    private void btnCalc_Click(object sender, EventArgs e)
    {
        //取得的正整數
        int currNum = 0;
        if (!int.TryParse(txtInputInt.Text, out currNum))
        {
            MessageBox.Show("必須輸入一個正整數數字!");
            return;
        }


        //清楚執行結果
        txtFinalResult.Clear();


        btnStartCalc.Enabled = false; //將【進行運算】按鈕啟用狀態取消
        btnCancel.Enabled = true; //將【取消非同步任務】按鈕啟用狀態啟用


        //用於顯示報告進度條的變數
        IProgress<int> progRpt = new Progress<int>((p) =>
        {
            this.progressBar1.Value = p;
        });


        //如果 CancellationTokenSource 物件變數不是為 null , 比較進行釋放(務必)
        if (cts != null)
         {
            cts.Dispose();
        }


        //實體化 CancellationTokenSource 物件
        cts = new CancellationTokenSource();


        //宣告一個任務變數
        Task<string> task = new Task<string>(() =>
        {
            BigInteger bint = new BigInteger(1d);
            double totalProgress = (double)currNum;


            //如果CancellationTokenSource 物件的 IsCancellationRequested 值為 true ,代表使用者已經將非同步任務進行取消
            for (int i = 1; i <= currNum && !cts.IsCancellationRequested; i++)
            {
                 bint *= i; //相乘
                double progressVal = Convert.ToDouble(i) / totalProgress * 100d;


                //顯示非同步任務執行的進度表
                progRpt.Report(Convert.ToInt32(progressVal));
            }


            //傳回執行結果
            return bint.ToString();


        }, cts.Token, TaskCreationOptions.LongRunning);

        //開始執行非同步任務
        task.Start();


        //等待任務操作完成,等待1秒
        while (!task.Wait(1000))
        {
            Application.DoEvents();
        }


        //顯示運算結果
        txtFinalResult.Text = task.Result;
        btnStartCalc.Enabled = true;
        btnCancel.Enabled = false;
    }


    private void btnCancel_Click(object sender, EventArgs e)
    {
         //使用者執行取消非同步任務
        if (cts != null)
        {
             cts.Cancel();
        }
    }
}


1
2
3

4

4.經過步驟3核心程式碼後,就可以編譯執行,執行結果畫面如下:
4-1.
執行運算中…
r1

4-2.
中途,我執行【取消非同步任務】按鈕
r2
完成上述這樣的示範,就可以撰寫讓使用者中途取消任務的執行。


參考文章
C#多工作業與平行處理技術講解
1.透過 Thread 類別撰寫多執行緒多工作業。
2.透過 Delegate 委託支援的方法,撰寫非同步任務。
3-1.透過 Parallel 類別操控多任務平行作業(一)。
3-2. 透過 Parallel 類別操控多任務平行作業(二)。
4.使用 Task 自行控制非同步任務作業。 
5.在非同步作業時,如何取消非同步任務。 
6.多執行緒多任務存取相同變數,但卻各自隔離保留各自任務的值。
7.非同步存取變數的問題。
8.非同步資源鎖定解決方式。





網智數位-軟體開發(軟件開發) 
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
公司電話:02-55991310
公司地址(業務營運處):台北市中山區錦州街 25 號 5 樓
skype: netqna
line:netqna
微信:netqna
黃先生 Allen

2017年2月7日 星期二

微軟可能推出 Win10雲端版系統 (軟體開發、軟體客制化、ERP 軟體)

      微軟正在開發新的Windows 10雲端版,有望成為該公司針對Chromebook發起的最新挑戰,而這款系統的最新版本已經在網上洩露。

Cfem-fyafqxp5657404

據多家媒體報導,Windows 10雲端版是一款輕系統,可能是針對微軟的ARM戰略設計的。一個 Twitter用戶在網上披露了Windows 10雲端版的ISO鏡像文件,甚至可以直接下載安裝。但業內人士推薦在虛擬機上安裝這款系統。


與之前的報導相同,Windows 10雲端版只允許用戶運行通過Windows Store購買的UWP應用,如果安裝其他應用則會顯示“不適配該系統”的提示信息。另外,系統對話框還會提醒用戶,“該版本希望保護您及您的設備,而且只能運行Windows Store應用。”

但值得注意的是,用戶可以從Windows Store下載部分Win32應用。這些Win32應用是通過微軟自己的桌面應用轉化器進駐Windows Store的,因此雖然可以通過Windows Store下載,但卻無法真正安裝在Windows 10雲端版上。

由於這只是早期版本的Windows 10雲端版,所以現在還不能完全確定微軟不允許用戶運行通過Windows Store下載的Win32應用。微軟有可能會在不遠的將來支持這項功能。

業內人士認為,Windows 10雲端版繼承了Windows RT的“遺志”,後者因為Windows Store的應用數量較少而未能取得成功。然而,從Windows Store和UWP應用的現狀來看,目前似乎與之前並無太​​大不同,很多用戶仍然非常依賴經典的Win32應用。

Windows 10雲端版可能幫助微軟與穀歌Chromebook直接競爭,通過廉價Windows 10設備提供一流的性能和順暢的用戶體驗。

網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
公司電話:02-55991310
skype: netqna
line:netqna
微信:netqna
黃先生 Allen

2016年11月11日 星期五

繪圖程式-折線圖、區域圖 實作一(軟體設計、軟體開發、程式開發)

        這半年來一直不斷被客戶要求開發相關繪圖功能的程式,礙於現在很多程式開發人員,已經越來越多人只會資料庫的CRUD,對於繪圖程式撰寫掌握度不是很好,甚至基本觀念也沒有,所以大多數程式開發人員都是去找相關的Chart套件,也很少有人示範在 Windows 10 APP 如何開發相關繪圖程式功能(很抱歉目前Windows 10 似乎沒有提供相關繪圖控制箱可以直接使用,所以要真的自己寫繪圖功能),所以我這篇就來教導如何在 Windows Universal APP 開發一個 折線圖功能,折線圖在軟體應用上面常用於股票分析、統計分析、銷售分析、趨勢走向等圖表展現。

(折線圖)
r-data-exploration-and-visualization-line-plot-1


(區域圖)
886d1a27-3744-417b-a3e5-e9b9878e5760



折線圖原理其實就是在一個二維的空間(平面)中,利用多個 【X,Y】坐標點透過直線連結起來,所形成的趨勢圖形,通常 X 軸代表一個某種類別例如月份、年份、型別等,而Y軸代表某類別的實際值,例如業績、銷售量、收入、人數等。在折線圖中,X軸都呈現等量(距)的增加。
現在我們知道了簡單的折線圖原理後,在Windows 10 (UWP)平台開發上,是必須使用 Polyline 繪圖技術來進行開發,可以在界面直接選告 XAML 語法,例如底下Code:

<Polyline Stroke=“Blue” StrokThickness="3”Points=”5,10 20,30 25,40 100,120”/>

其中最重要的來自于 Points 屬性 ,5,10 =》代表一個點 [5,10] =>X=5,Y=10
但通常在開發繪圖功能時,都是動態繪圖產生,所以在這邊我也示範如何完全在背後使用程式開發一個折線圖功能,我在界面上我簡單的設計2個按鈕,分別作為繪製 折線圖跟區域圖,前端界面如下

image


//XAML Code
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="100"/>
            <RowDefinition Height="Auto"/>

        </Grid.RowDefinitions>
        <StackPanel  Grid.Row="0" Orientation="Horizontal">
            <Button Content="折線圖繪製" Click="DrawChart_1" Margin="12" Background="AliceBlue"></Button>
            <Button Content="區域圖繪製" Click="DrawChart_2" Margin="12" Background="Wheat"></Button>
        </StackPanel>
        <Grid x:Name="gdChartCanvas" Grid.Row="1" Height="auto" HorizontalAlignment="Center" VerticalAlignment="Center">

        </Grid>
</Grid>



在後端的程式碼,分別設計了 GetAllPoints()方法、與對應的 DrawChart_1 、DrawChart_2 事件方法

       /// <summary>
       /// 取得所有折線圖、區域圖的 Y值清單
       /// </summary>
       /// <param name="yValues">Y值清單</param>
       /// <param name="perWidth">X等距寬度</param>
       /// <param name="yStartValue">Y起始值</param>
       /// <returns></returns>
       private PointCollection GetAllPoints(List<double> yValues, double perWidth, double yStartValue)
       {
           PointCollection points = new PointCollection();
           double x = 0;

           foreach (double yVal in yValues)
           {
               double y;

               //判斷 Y 值是否小於 Y坐標起始值,因為畫布是從 100 開始
               if (yVal < yStartValue)
               {
                   y = 100;
               }
               else
               {
                   //可以套用自己的公式來設定Y值
                   //y = Math.Floor((500 - (yVal * 200) / 300));
                   y = yVal;
               }

               Point point = new Point(x, y);
               points.Add(point);
               x += perWidth;
           }

           return points;
       }


      /// <summary>
      /// 繪製折線圖
      /// </summary>
      /// <param name="sender"></param>
      /// <param name="e"></param>
      private void DrawChart_1(object sender, RoutedEventArgs e)
      {
          //清除畫布
          this.gdChartCanvas.Children.Clear();

          //Y值清單
          List<double> datas = new List<double> { 185, 130, 230, 140, 200, 60, 170, 150, 190, 150, 110, 220, 130, 190, 150 };

          //取得套用公式的Y轉變值
          PointCollection pointCollection = GetAllPoints(datas, 45, 100);

          Polyline polyline = new Polyline { Points = pointCollection, Stroke = new SolidColorBrush(Colors.Red) };
          this.gdChartCanvas.Children.Add(polyline);
      }




上述程式撰寫完畢後,就可以直接點選【折線圖繪製】按鈕,畫面馬上呈現折線圖,如下執行結果

image
image







網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
skype: netqna
line:netqna
微信:netqna
黃先生 Allen






2016年11月6日 星期日

Windows 10 UWP 存取 JSON 格式 - 程式實作講解(軟體開發、客製化軟體、程式設計、程式開發)

      在我們開發各種專案時,一定多少都會需要存取各種跨平台傳輸的資料,目前最普遍的傳輸格式為 XML 與 JSON , 而今天我想要深入講解在 Windows 10 Universal APP (UWP)平台下,如何讀取跟儲存 JSON 格式資料。

      images


    JSON 的全名為 Java Script Object Notation , 它是一種輕量級的資料傳輸交換格式語言,特點是容易閱讀、依字串為基礎,格式都是經過壓縮地所以在網路傳輸過程,佔用的頻寬極小,因此被廣泛地應用在跨平台、跨程式語言。
JSON 的格式在宣告一個類別/物件,是用 大括號 { };宣告一個陣列使用 中括號 [ ] ;而在大括號裡面,是使用 名稱 :值 ,下圖是官方的範例圖解釋
1356331778-696014507


例如 我在此 有個 員工類別 ,分別屬性有員工編號、姓名、職位、學歷,則對應的 JSON 格式為 
(JSON Code)
var empJsonObj = { “員工編號”:“emp001”, “姓名”: “台灣李奧納多,”“職位”: “技術總監”,"年齡”:33 } ;

接下來,就是要開始講解如何在 Windows 10 Universal APP (UWP)平台,存取 JSON 格式的支援與程式開發技巧。
在 Windows 10 UWP 平台,主要有 2 種技巧來存取 JSON 格式,第一種是使用 DataContractJsonSerializer (MSDN 介紹),透過 DataContractJsonSerializer 來對 JSON 數據進行序列化與反系列化動作 ;而第二種是使用 JsonObject 類別來自行定義 JSON 物件。這兩種方式我都會在這篇完整介紹。


1.透過 DataContractJsonSerializer 對 JSON 資料進行序列化與反序列化
      使用 DataContractJsonSerializer 類別來對 JSON 數據進行序列化與反序列化,這是最簡單的方式,所謂序列化過程就是把 實體類別物件 轉成 JSON 格式化的字串,反之 反序列化 過程,就是把 JSON 物件字串({ 名稱:值,名稱1:值1….}) 轉換成對應的 .NET 類別。

下圖,是實際程式範例
image


image



2.透過使用 JsonObject 類別來自行定義 JSON 物件
這個就讓我直接用實際程式碼來講解….
首先我先新增2個類別 ,分別為 員工類別 (Employee)和研發群組類別(RDGroup),在此我假設一個員工可以同時歸屬多於于一個研發群組以上。

底下為 員工類別程式碼:

   /// <summary>
   /// 員工類別
   /// </summary>
   public class Employee
   {
       private const string idKey = "id";
       private const string nameKey = "name";
       private const string rdKey = "rd";
       private const string ageKey = "age";
       private const string enableKey = "enable";

       public Employee()
       {
           Id = "";
           Name = "";
           RDGroups = new ObservableCollection<RDGroup>();
       }

       public Employee(string jsonString) : this()
       {
           JsonObject jsonObject = JsonObject.Parse(jsonString);
           Id = jsonObject.GetNamedString(idKey, "");
           Name = jsonObject.GetNamedString(nameKey, "");
           Age = jsonObject.GetNamedNumber(ageKey, 0);
           Enable = jsonObject.GetNamedBoolean(enableKey, false);

           foreach (IJsonValue jsonValue in jsonObject.GetNamedArray(rdKey, new JsonArray()))
           {
               if (jsonValue.ValueType == JsonValueType.Object)
               {
                   RDGroups.Add(new RDGroup(jsonValue.GetObject()));
               }
           }
       }
       public string Stringify()
       {
           JsonArray jsonArray = new JsonArray();
           foreach (RDGroup group in RDGroups)
           {
               jsonArray.Add(group.ToJsonObject());
           }

           JsonObject jsonObject = new JsonObject();
           jsonObject[idKey] = JsonValue.CreateStringValue(Id);
           jsonObject[nameKey] = JsonValue.CreateStringValue(Name);
           jsonObject[rdKey] = jsonArray;
           jsonObject[ageKey] = JsonValue.CreateNumberValue(Age);
           jsonObject[enableKey] = JsonValue.CreateBooleanValue(Enable);

           return jsonObject.Stringify();
       }

       public string Id { get; set; }
       public string Name { get; set; }
       public ObservableCollection<RDGroup> RDGroups { get; set; }
       public double Age { get; set; }
       public bool Enable { get; set; }

   }

底下為 研發群組類別(RDGroup)程式碼:

  /// <summary>
  /// 研發群組 類別,一個員工可以歸屬多個研發群組
  /// </summary>
  public class RDGroup
  {
      private const string idKey = "id";
      private const string rdKey = "rd";
      private const string nameKey = "name";

      public RDGroup()
      {
          Id = "";
          Name = "";
      }

      public RDGroup(JsonObject jsonObject)
      {
          JsonObject schoolObject = jsonObject.GetNamedObject(rdKey, null);
          if (schoolObject != null)
          {
              Id = schoolObject.GetNamedString(idKey, "");
              Name = schoolObject.GetNamedString(nameKey, "");
          }
      }

      public JsonObject ToJsonObject()
      {
          JsonObject schoolObject = new JsonObject();
          schoolObject.SetNamedValue(idKey, JsonValue.CreateStringValue(Id));
          schoolObject.SetNamedValue(nameKey, JsonValue.CreateStringValue(Name));

          JsonObject jsonObject = new JsonObject();
          jsonObject.SetNamedValue(rdKey, schoolObject);
          return jsonObject;
      }

      public string Id { get; set; }
      public string Name { get; set; }
  }



再來我設計一個前端UI界面,作為讀取與寫入 JSON 的案例實作

前端界面
image



在執行存檔時,我們將新增一個 Employee 類別,並透過 JsonObject 轉成(序列化)為 JSON 字串,儲存在設定檔。
image

而在【讀取資料】時,是透過 JsonObject 進行反序列化,將 Json String 轉回成 .Net 的 Employee 類別(Class)
image



程式執行結果畫面
存檔
image


讀取資料
image






網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:allen@netqna.com
聯繫電話:0920-883-870
skype: netqna
line:netqna
微信:netqna
黃先生 Allen





2016年10月27日 星期四

Windows 10 的 UDP 與 TCP 網路通訊實作案例二(軟體開發、軟件開發、程式設計、程式開發)

      這篇文章主要是續之前另外一篇文章 UDP 網路通訊處理,這次是繼續講解 TCP 網路通訊處理,與UDP 協定不同的是,TCP協定是更加嚴謹,它是基於確認連接是可靠性的,也就是在發生通訊傳輸前,客戶端(Client)必須確認是連接到伺服器(Server)端,因為 TCP 對數據封包的次序與完整性要求相對嚴格,這樣才能確保數據傳輸過程可以正確無誤地送達目的地,所以 TCP 就常用在 文件的傳送,如Line聊天的檔案傳送、Skype 檔案的傳送等。






     在 Widnows 10 Universal APP 平台下(UWP ),是透過一個 StreamSocket 類別來提供 TCP 網路通訊傳輸協定的 Socket 功能.
在 Client 端(客戶端)大致我們遵守以下幾個步驟:
1.建立一個 StreamSocket 實體物件。
2.呼叫 StreamSocket.ConnectAsync 方法,來與 Server 端作連接要求。
3.使用 OutputStream 屬性所返回的輸出流(Stream),就可以進行發送資料;
    而 InputStream 屬性則是返回輸入流,是用在接受資料。
4.切記當不再使用 Socket 時,呼叫 Dispose 方法來釋放其所佔用的相關資源。

在 Server 端 (伺服器),我們則需要使用一個 StreamSocketListener 物件,綁定繫結 本機的位址跟Port,來監聽 客戶端(Client)的連接請求服務,而當監聽到客戶發出的請求服務時,會引發另外一個事件 ConnectionReceived 事件,從這個事件的Arg參數,我們可以獲取一個與客戶端進行通訊的 StreamSocket 物件。

上面簡單描述原理,以及程式撰寫大致步驟原理,我一樣習慣來個實際寫作案例來引導,我一樣為了簡單化,我把 Server 端界面與 Client 端界面放在一起,這樣這個範例程式可以充當伺客戶器角色也可以當客戶端角色,在實作案例中 客戶端可以選擇一個圖片已經輸入一些文字內容來描述圖片,最後可以發送圖片跟文字內容給伺服器端,當然伺服器端會馬上監聽到有傳輸服務請求,立即結束資料,並顯示在伺服器端的界面。
系統畫面如下圖

(Server 端)
image


(Client 端)
image



下面是相關的界面 XAML Code:

<Pivot>
           <PivotItem Header="伺服器(Server 端模擬)">
               <Grid>
                   <Grid.RowDefinitions>
                       <RowDefinition Height="Auto"/>
                       <RowDefinition />
                   </Grid.RowDefinitions>
                   <StackPanel>
                       <TextBlock Text="Server IP Address:" Height="30" Margin="0,0,-0.333,0"/>
                       <TextBlock x:Name="tbSvIP" FontSize="24" IsTextSelectionEnabled="True" Height="30" Margin="0,0,-0.333,0"/>
                   </StackPanel>
                   <ListBox Name="lbItems" Grid.Row="1" Margin="6,15,6,5">
                       <ListBox.ItemTemplate>
                           <DataTemplate>
                               <Grid>
                                   <Grid.ColumnDefinitions>
                                       <ColumnDefinition Width="Auto"/>
                                       <ColumnDefinition/>
                                   </Grid.ColumnDefinitions>
                                   <Image Width="50" Height="50" Stretch="UniformToFill" Source="{Binding Path=Image}"/>
                                   <TextBlock Grid.Column="1" TextWrapping="Wrap" FontSize="18" Text="{Binding Path=Text}" Margin="15,0,0,0"/>
                               </Grid>
                           </DataTemplate>
                       </ListBox.ItemTemplate>
                   </ListBox>
               </Grid>
           </PivotItem>
           <PivotItem Header="客戶端(Client 端模擬)">
               <StackPanel>
                   <TextBox Name="txtServerIp" Header="伺服器IP:"/>
                   <Image Name="img" Width="150" Height="150" HorizontalAlignment="Left"/>
                   <Button Content="挑選圖片..." Click="OnPickImagFile"/>
                   <TextBox Name="txtContent" Header="圖片描述:" Height="120"/>
                   <Button Content="傳送資料" HorizontalAlignment="Stretch" Click="OnSend"/>
               </StackPanel>
           </PivotItem>
       </Pivot>


現在來看主要核心程式碼 
一開始我宣告 一個 LISTEN_PORT=“1688”,作為 Server 端監聽的端口。
然後也宣告一個 StreamSocketListener 類別的 listener 欄位。
相關程式我也詳細註解了,主要是在 Loaded事件時,建立對應的監聽事件 ConnectionReceived 、以及使用 BindServiceNameAsync 方法指定監聽的Port。
image


接下來重點在 ConnectionReceived 事件,專門用於接受到 Client 端發出的請求數據。

private async void listener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
       {
           string text = string.Empty;
           IRandomAccessStream imgStream = new InMemoryRandomAccessStream();

           // 處理從 Client 端接受到的訊息
           using (StreamSocket socket = args.Socket)
           {
               using (DataReader reader = new DataReader(socket.InputStream))
               {
                   try
                   {
                       // 讀出第一個數字,表示文件的長度
                       await reader.LoadAsync(sizeof(uint));
                       uint len = reader.ReadUInt32();
                       await reader.LoadAsync(len);
                       IBuffer buffer = reader.ReadBuffer(len);
                       // 寫入 Stream
                       await imgStream.WriteAsync(buffer);
                       await reader.LoadAsync(sizeof(uint));
                       // 再次讀入字串長度
                       len = reader.ReadUInt32();
                       // 讀出字串的內容
                       if (len > 0)
                       {
                           await reader.LoadAsync(len);
                           text = reader.ReadString(len);
                       }
                   }
                   catch (Exception ex)
                   {
                       DisplayErrMessage(ex.Message);
                   }
               }
           }

           // 顯示接受到的客戶端訊息內容
           await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
               {
                   BitmapImage bmp = new BitmapImage();
                   bmp.DecodePixelWidth = 50;
                   imgStream.Seek(0);
                   bmp.SetSource(imgStream);
                   imgStream.Dispose();
                   lbItems.Items.Add(new { Image = bmp, Text = text });
               });
       }


再來 Client 端,主要是選好圖片內容、以及輸入文字描述後,執行【傳送資料】按鈕,而對應的程式碼,如下,我也寫上對應的註解
private async void OnSend(object sender, RoutedEventArgs e)
       {
           if (txtServerIp.Text.Length == 0)
           {
               DisplayErrMessage("請輸入伺服器服的IP位置");
               return;
           }
           IBuffer bufferImg = img.Tag as IBuffer;
           if (bufferImg == null)
           {
               DisplayErrMessage("請選擇圖像");
               return;
           }
           Button b = sender as Button;
           b.IsEnabled = false;

           using (StreamSocket socket = new StreamSocket())
           {
               try
               {
                   // 發出連線請求
                   await socket.ConnectAsync(new HostName(txtServerIp.Text), LISTEN_PORT);
                   // 準備傳送資料(圖片跟文字)
                   using (DataWriter writer = new DataWriter(socket.OutputStream))
                   {
                       // 首先寫入圖片
                       uint len = bufferImg.Length;
                       writer.WriteUInt32(len); //長度
                       writer.WriteBuffer(bufferImg);
                       // 寫入文字內容
                       if (txtContent.Text.Length == 0)
                       {
                           writer.WriteUInt32(0);
                       }
                       else
                       {
                           len = writer.MeasureString(txtContent.Text);
                           writer.WriteUInt32(len); //長度
                           writer.WriteString(txtContent.Text);
                       }
                       // 正式提交
                       await writer.StoreAsync();
                   }
                   txtContent.Text = "";
               }
               catch (Exception ex)
               {
                   DisplayMessage(ex.Message);
               }
           }
           b.IsEnabled = true;
       }
 


整個程式執行結果畫面 
(客戶端)

image












(伺服器端) 



網智數位-軟體開發(軟件開發)
針對各特殊產業都可以量身定做符合貴公司的需求,別人無法克服的就是我們的挑戰
業務合作、軟體委外開發
業務窗口:
allen@netqna.com
聯繫電話:0920-883-870
skype: netqna
line:netqna
微信:netqna
黃先生 Allen