StreamSoketのSampleコード

非同期化していないところがあったりするのであまりいいサンプルではないですが、StreamSoketでの通信コードです。
WriteAsync、LoadAsyncで書き込み/読み込みを行うようにしてあります。
DataReader、DataWriterを使用した際にうまくいかなかったので、このような形で実装しています。

///////////////////////////////////////////////////////////////////////////////////////////////
// サーバへ接続等

        #region サーバへ接続
        /// <summary>
        /// TCPでサーバへ接続
        /// </summary>
        /// <param name="hostname"></param>
        /// <param name="serverport"></param>
        public async void TcpSocketConnect(string hostname, string serverport)
        {
            SocketStatusEventArgs socketevent = new SocketStatusEventArgs();

            // 接続済み
            if (SocketDatacontext.Connected)
            {
                socketevent.SocketStatus = StringResourceLoader.GetString("Already");
                OnSocketStatus(socketevent);
                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus);
                await Task.Run(() => { throw new PopClassException(SocketDatacontext.SocketMessage); });
                return;
            }

            if (SocketDatacontext.TcpSocket == null)
            {
                SocketDatacontext.TcpSocket = new Windows.Networking.Sockets.StreamSocket();

                bool currentSetting = SocketDatacontext.TcpSocket.Control.NoDelay;
                SocketDatacontext.TcpSocket.Control.KeepAlive = true;
                SocketDatacontext.TcpSocket.Control.NoDelay = false;
            }

            try
            {
                /// タイムアウト用
                CancellationTokenSource cts = new CancellationTokenSource();

                socketevent.SocketStatus = StringResourceLoader.GetString("Trying");

                OnSocketStatus(socketevent);

                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus); 
                
                var serverHost = new HostName(hostname);

                // タイムアウトの設定
                cts.CancelAfter(10000);

                await SocketDatacontext.TcpSocket.ConnectAsync(serverHost, serverport).AsTask(cts.Token);

                // DataReaderの作成
                SocketDatacontext.PeerReader = new DataReader(SocketDatacontext.TcpSocket.InputStream);
                SocketDatacontext.PeerReader.InputStreamOptions = InputStreamOptions.Partial;

                SocketDatacontext.Connected = true;
                SocketDatacontext.Closing = false;
                socketevent.SocketStatus = StringResourceLoader.GetString("Connection");
                OnSocketStatus(socketevent);
                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus);
            }
            catch (Exception ex)
            {
                socketevent.SocketStatus = StringResourceLoader.GetString("Connecterror") + ex.Message;
                OnSocketStatus(socketevent);

                SocketDatacontext.Closing = true;
                SocketDatacontext.TcpSocket.Dispose();
                SocketDatacontext.TcpSocket = null;
                SocketDatacontext.Connected = false;

                OnSocketStatus(socketevent);
                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus);
                throw new PopClassException(SocketDatacontext.SocketMessage);
            }
        }
        #endregion

///////////////////////////////////////////////////////////////////////////////////////////////
// サーバへデータを送る

        #region サーバへデータを送る
        public async void ResultSend(string req)
        {
            SocketStatusEventArgs socketevent = new SocketStatusEventArgs();

            if (!SocketDatacontext.Connected)
            {
                socketevent.SocketStatus = StringResourceLoader.GetString("Mustbeconnectedtosend");
                OnSocketStatus(socketevent);

                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus);
                return;
            }

            try
            {
                // サーバへリクエスト送信
                if (req != "")
                {
                    StreamSocketLib writeSokect = new StreamSocketLib();

                    socketevent.SocketStatus = StringResourceLoader.GetString("Tryingtosenddata");
                    OnSocketStatus(socketevent);

                    writeSokect.DataSend(SocketDatacontext.TcpSocket, req);

                    cryearthlib.DebugLoging.DebugPrint("Data Writer End");
                }
            }
            catch (Exception exception)
            {
                socketevent.SocketStatus = "Send data or receive failed with error: " + exception.Message;
                OnSocketStatus(socketevent);
            }
        }
        #endregion
        /// <summary>
        /// データ書き込みフロント
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="senddata"></param>
        public void DataSend(StreamSocket socket, string req)
        {
            _socket = socket;

            Encoding encoding = Encoding.UTF8;

            byte[] bydata = encoding.GetBytes(req + Environment.NewLine);

            if (socket == null)
            {
                cryearthlib.DebugLoging.DebugPrint("socket Error : socket null");
                throw new Exception("socket Error : socket null");
            }

            try
            {
                var task = SocketDataWrite(bydata);
                if (!task.IsCompleted)
                {
                    var ret = task.Wait(timeout);
                    if (!ret)
                    {
                        cryearthlib.DebugLoging.DebugPrint("Write Time Out");
                    }
                }

                if (!task.Result)
                {
                    cryearthlib.DebugLoging.DebugPrint("Write Time Out");
                }
            }
            catch (Exception ex)
            {
                cryearthlib.DebugLoging.DebugPrint("DataWrite Error : " + ex.Message);
                throw new Exception("DataWrite Error : " + ex.Message);
            }
        }

        /// <summary>
        /// データ書き込み本体
        /// </summary>
        /// <param name="senddata"></param>
        /// <returns></returns>
        public async Task<bool> SocketDataWrite(byte[] senddata)
        {
            var writeTask = _socket.OutputStream.WriteAsync(senddata.AsBuffer()).AsTask();

            if (!writeTask.IsCompleted)
            {
                var writeret = writeTask.Wait(timeout);
                if (!writeret)
                {
                    return false;
                }
            }

            var flushTask = _socket.OutputStream.FlushAsync().AsTask();

            if (!flushTask.IsCompleted)
            {
                var flushret = flushTask.Wait(timeout);
                if (!flushret)
                {
                    return false;
                }
            }
            return true;
        }



///////////////////////////////////////////////////////////////////////////////////////////////
// サーバからのデータを読み込む

        #region サーバからのデータを読み込む
        public async Task<string> ResultRead()
        {
            SocketStatusEventArgs socketevent = new SocketStatusEventArgs();

            if (!SocketDatacontext.Connected)
            {
                socketevent.SocketStatus = StringResourceLoader.GetString("Mustbeconnectedtosend");
                OnSocketStatus(socketevent);

                return null;
            }

            try
            {
                var lastChar = string.Empty;
                var fullString = string.Empty;

                cryearthlib.Sleep(200);
                
                socketevent.SocketStatus = StringResourceLoader.GetString("Tryingtosenddata");
                OnSocketStatus(socketevent);

                CancellationTokenSource cts = new CancellationTokenSource(1000);
                cts.Token.ThrowIfCancellationRequested();
                var bytesRead = SocketDatacontext.PeerReader.LoadAsync(1024);

                Debug.WriteLine("StreamWriteAndRead : reader.LoadAsync : " + bytesRead.Status.ToString());

                if (bytesRead.Status != Windows.Foundation.AsyncStatus.Completed)
                {
                    cts.Cancel();

                    Debug.WriteLine("StreamWriteAndRead : cts.Cancel");
                    Debug.WriteLine("StreamWriteAndRead : " + bytesRead.Status.ToString());
                }
                else
                {
                    Debug.WriteLine("StreamWriteAndRead : ReadString : " + bytesRead.Status.ToString());

                    while (SocketDatacontext.PeerReader.UnconsumedBufferLength > 0)
                    {
                        fullString += SocketDatacontext.PeerReader.ReadString(SocketDatacontext.PeerReader.UnconsumedBufferLength);
                    }
                }

                SocketDatacontext.SocketMessage = socketevent.SocketStatus = fullString;
                OnSocketStatus(socketevent);

                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus);
                cryearthlib.DebugLoging.DebugPrint("reader.End");
                return fullString;
            }
            catch (Exception exception)
            {
                socketevent.SocketStatus = "Receive failed with error: " + exception.Message;
                OnSocketStatus(socketevent);
                cryearthlib.DebugLoging.DebugPrint(socketevent.SocketStatus);
                return socketevent.SocketStatus;
            }
        }
#endregion

Unity4.2が出てた

学習用に入れてたんですが、Unity4.2が出ていました。
大きな違いとしては「WindowsStoa」と「WindowsPhone8」向けのbuildが可能になったようです。

unity

buildの際に、専用のフォルダを作成して指定しないとbuildされないような気配です。

作製すると、VS2012用のソリューションファイルが作成されているので、VSで開き、WindowsPhone8実機に転送実行になります。

吐き出したUnityPlayerがARMのみのようなため実機(デバイス)での実行に制限されるようです。

ストアアプリ向けbuildを試したところ、エラーが発生して作成できませんでした。
エラーが文字化けしているため何でエラーなのかがちょっと不明ですが、ArrayList、Hashtableで起きています。
WP8用にbuildした際は通っているので、何かしらの制限かとも思うのですが不明です。

Unity勉強しないとな、、、

GridのRow、Columnに合わせてドラッグ移動

とりあえずドラッグの方向に合わせて移動
これだけだと過敏すぎるので移動量か移動先のRow、Column数値をとって行うとかしないとだめだと思う。

GridViewItemでDragItemThemeAnimationなんかの組み合わせのほうがいいような気もする

またはこれで行ってる「SetValue(Grid.ColumnProperty,~)」を利用してオセロや囲碁などのほうが現実的かもしれない。

        private void MainChara_ManipulationDelta(object sender, Windows.UI.Xaml.Input.ManipulationDeltaRoutedEventArgs e)
        {
        	// TODO: ここにイベント ハンドラーのコードを追加します。
            // MainChara.SetValue(Grid.RowProperty, 3);
            var radian = Math.Atan2(e.Delta.Translation.Y, e.Delta.Translation.X);
            double degree = radian * 180.0 / 3.141592653589793;

            if (degree < 0)
            {
                degree += 360;
            }

            if (degree > 315 && degree < 380)
            { 
                // 右
                var value = (int)MainChara.GetValue(Grid.ColumnProperty);
                if (value != 6)
                {
                    value++;
                    MainChara.SetValue(Grid.ColumnProperty, value);
                }
            }
            else if (degree > 0 && degree < 45)
            {
                // 右
                var value = (int)MainChara.GetValue(Grid.ColumnProperty);
                if (value != 6)
                {
                    value++;
                    MainChara.SetValue(Grid.ColumnProperty, value++);
                }
            }
            else if (degree > 45 && degree < 135)
            { 
                // 下
                var value = (int)MainChara.GetValue(Grid.RowProperty);
                if (value != 6)
                {
                    value++;
                    MainChara.SetValue(Grid.RowProperty, value);
                }
            }
            else if (degree > 135 && degree < 225)
            {
                // 左
                var value = (int)MainChara.GetValue(Grid.ColumnProperty);
                if (value != 0)
                {
                    value--;
                    MainChara.SetValue(Grid.ColumnProperty, value);
                }
            }
            else
            {
                // 上
                var value = (int)MainChara.GetValue(Grid.RowProperty);
                if (value != 0)
                {
                    value--;
                    MainChara.SetValue(Grid.RowProperty, value);
                }
            }
        }

多言語対応アプリ提出時の注意点

Windowsストアアプリ/WindowsPhoneアプリを多言語に対応させてストアへ提出する場合の注意点。
・スクリーンショットは全言語用に同じだけ用意する。
・スクリーンショットの説明は全言語で共通の内容を翻訳して記載する。

プロモーション画像やタイトルアイコン、スプラッシュ画像はよほどでない限り共通でも行ける模様。
・タイトルに漢字を使って目立たせてるのでなどの理由は必要だと思いますが、可能でした。

後から言語を増やした場合は、すでに登録済みの言語に対しての更新内容に「対応言語を増やしました」という記載をしたほうがよい。
・追加した言語は「最初の公開」でも大丈夫でした。

Windowsストアアプリでの物理キーボードの有無

物理キーボードの有無を確認することで、「キーボード操作」とタブレットでの「コントローラーUI操作」の表示切替を実装することができる。

「KeyboardCapabilities Class」を使用して確認
「KeyboardPresent」が読み取り専用であるので、これを確認すること。

下記のページで確認したもの
http://msdn.microsoft.com/ja-jp/library/windows/apps/windows.devices.input.keyboardcapabilities.aspx

Windowsストアアプリで使用できるグラフコントロール

Modern UI (Metro) Charts for Windows 8, WPF, Silverlight
License:Microsoft Public License (Ms-PL)

・これから調べる

WinRT XAML Toolkit
License:The MIT License (MIT)
上記のチャートは「Windows 8 Toolkit – Charts and More(License:Common Development and Distribution License (CDDL))」からのポート
・これから調べる
・WinRT XAML ToolkitはどうやらWin8.1ベースでVS2013になっている模様

どちらもベータで、「Modern UI (Metro) Charts for Windows 8, WPF, Silverlight」には折れ線グラフはまだない

有料であれば、下記のようなものもあります。
NetAdvantage for Windows UI

デスクトップでWindowsRuntimeAPIを使う場合の忘備録

MSエヴァンジェリストのVS魂100連発から
http://www.youtube.com/watch?v=xmwTbfWKDyA

・最初の設定
デスクトップアプリのプロジェクトをいったん「プロジェクトのアンロード」を行う
アンロードしたプロジェクトを右クリックして「.csprojの編集」をクリック
「PropertyGroup」内に「TargetPlatformVersion」を追加して「8.0」とする
上書き保存したらプロジェクトを再読み込みする
「参照設定」から「参照の追加」をクリックすると左側に「Windows」が増えているのでコアから「Windows」を追加
「ブラウズ」から「参照」で「\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5」から「System.Runtime.dll」を追加する。
「using Windows.Foundation;」を追加する。
「System.Runtime.dll」は.NETのCollectionとRTのCollectionに互換性がないため、その互換変換のために必要になる。

・async/awaitの非同期に対応する
「参照設定」から「参照の追加」をクリック
「ブラウズ」から「参照」で「\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5」から「System.Runtime.WindowsRuntime.dll」「System.Threading.Tasks.dll」の二つを追加
これを追加することで「async/await」が使用可能になる。
使わない場合「IAsyncOperation」をもとに書くようにする。

今更ながらの忘備録、これでストアアプリ管理ツールの作成などにもWindowsRuntimeAPIを使える。

indexを指定可能なIntデータCollectionProperty

collectionなPropertyにIndexを指定して通知したい場合に下記のように行う
通常ではIndex指定でやり取りはできないと思うのでメモがてら

    /// <summary>
    /// IntデータcollectionProperty
    /// </summary>
    public class CollectionDataProperty : CryEarth.lib.cryearthlib.NotifyPropertyChangedMethod
    { 
        private readonly Collection<int> items = new Collection<int>();

        public CollectionDataProperty()
        {
            items.Clear();
        }

        public int this[int index]
        {
            get
            {
                // indexの境界チェック
                if (items.Count < index)
                {
                    return 0;
                }
                return items[index];
            }
            set
            {
                //indexの境界チェック
                if (items.Count < index+1)
                {
                    items.Add(value);
                }
                else if (items[index] == value)
                {
                    return;
                }
                else
                {
                    items[index] = value;
                }
                OnPropertyChanged(ITEMS);
            }
        }

        private const string ITEMS = "Item[]";
    }

デバッグ用のメモ

TDDを徹底すればこれはあまり必要ないかもしれないが、あって困るものではないので、メモ代わりに書いておく
公式サンプルなどから集めたものなので、あまりきれいではない。
機能を追加するとすれば、ローカルストレージ(またはSQL)への保存機能を追加することで、追いかけやすくなるのではないかと思われる。

using System.Runtime.CompilerServices;
public static class DebugLoging
{
// WinRTコアイベントのDispatcher
// 使用する際は「Window.Current.Dispatcher;」を渡すこと
// debug情報ページをInFreamに読み込んでいる
public static CoreDispatcher coreDispatcher;
// 書き出しに使用するTextBlock
public static TextBlock debugOutputTextBlock;

// Cでのマクロ、__LINE__ , __FILE__ や
// C#(WindowsPhone)でのStackFram は使用できないので、
// C#5.0の「System.Runtime.CompilerServices」を使用する
public static async void DebugPrint(string msg,
[CallerFilePath] string file = "",
[CallerLineNumber] int line = 0,
[CallerMemberName] string member = "")
{
var fullMessage = string.Format("{0}:{1}\r\n\t{2}: {3}", file, line, member, msg);

Debug.WriteLine(fullMessage);

if (coreDispatcher != null)
{
await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
debugOutputTextBlock.Text =
debugOutputTextBlock.Text +
DateTime.Now.ToString(@"M/d/yyyy hh:mm:ss tt") + " " + fullMessage + "\r\n";
});
}
}
}

PageのFrame読み込みに関するメモ

PageをNavigationでそれぞれ個別ページ遷移呼び出しではなくFrameを宣言して、その中に読み込むことができる。
所謂HTMLでいうところの「iframe」のような形が可能

・元PageでのXAML宣言

<Frame x:name="otherPageFrame" />

・元ページでの呼び出し

otherPageFrame.Navigate(typeof(OtherPage), this);

PageをFrameとして入れ込んでいるため、各ページでコードを管理できるが、呼び出し順(Loadedイベントで特に)などで問題が起きやすいものと思われる
UIコントロールが有効になっていない時に読み込むことはできないので、当たり前とは思われる。
・直接LoadedイベントをXAMLに宣言せず、「InitializeComponent()」の後、または「OnNavigatedTo」でイベントを有効化する
・「OnNavigatedFrom」でイベントを解除するのを忘れないこと

//まだまとまっていないので、掘り下げること