echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

DataTableからListにデータを変換する方法

やりたいこと

  • DataTableの内容(主にデータベースのデータ)に対しても、ListみたいにLinqで扱いたい。

理由

  • ループで1行ずつList.Add()すれば出来るけど、Enumerable.ToList()みたいに スマートに実現出来ないか? (コードもシンプルになるし)
  • 何だかんだ言っても、.net製の業務システムではまだまだDataTable(DataSet)が 現役なので、 変換ができるようになっておくと便利。
  • DataTableとListでは、後者の方が処理が早いみたいなので。(※)

※参照:意外と遅い DataTable 、なので List を使うと 5 倍早くなる

いきなり結論

「AsEnumerable()」メソッドを使えばOK。(.net Framework3.5以降)
このメソッドを実施するとIEnumerableオブジェクトが戻り値として返されるので、 あとはToList()を実行すれば、Listに変換できる。

サンプルソース

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

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

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            // 今回はDataTable,DataRowCollectionは自前で用意。
            var dt = new DataTable();

            dt.Columns.Add("ORDER_NO");
            dt.Columns.Add("USER_NO");
            dt.Columns.Add("COUNTRY_CODE");
            dt.Columns.Add("PREF_CODE");

            var dr = dt.NewRow();

            dr["ORDER_NO"] = "0001";
            dr["USER_NO"] = "AAAA";
            dr["COUNTRY_CODE"] = "JPN";
            dr["PREF_CODE"] = "AIC";
            dt.Rows.Add(dr);

            var dr2 = dt.NewRow();

            dr2["ORDER_NO"] = "0002";
            dr2["USER_NO"] = "BBBB";
            dr2["COUNTRY_CODE"] = "USA";
            dr2["PREF_CODE"] = "LA";
            dt.Rows.Add(dr2);

            var dr3 = dt.NewRow();

            dr3["ORDER_NO"] = "1003";
            dr3["USER_NO"] = "CCCC";
            dr3["COUNTRY_CODE"] = "UK";
            dr3["PREF_CODE"] = "RD";
            dt.Rows.Add(dr3);

            var dr4 = dt.NewRow();

            dr4["ORDER_NO"] = "1004";
            dr4["USER_NO"] = "DDDD";
            dr4["COUNTRY_CODE"] = "FR";
            dr4["PREF_CODE"] = "Z";
            dt.Rows.Add(dr4);

            // ここから、DataTable→List<DataRow>への変換処理。

            // 単にList<DataRow>に変換する場合、ToList<DataRow>()を使用する。
            var list1 = dt.AsEnumerable().ToList<DataRow>();

            // AsEnumerable()を実行すれば、Listに変換する前に
            // Linqを使用することももちろん可能。

            // Where()でフィルタをかけたり...
            var list2 = dt.AsEnumerable()
                .Where(x => x["ORDER_NO"].ToString().Substring(0, 1) == "1")
                .ToList<DataRow>();

            // DataTableの各行のデータを編集して、Listにする事も可能。
            Func<DataRow, string> getRight = x =>  
             (x["PREF_CODE"].ToString().PadRight(2).Length <= 2) ?  
              x["PREF_CODE"].ToString().PadRight(2) : x["PREF_CODE"]  
              .ToString().Substring(1 ,2);

            var list3 = dt.AsEnumerable()
                .Select(x => x["ORDER_NO"].ToString() +  
                 x["COUNTRY_CODE"].ToString().PadRight(3) +  
                  getRight(x)).ToList<String>();
        }
    }
}

今回は少し短めですが、ちょっとC#について調べましたよ...ってことで。

Listに参照型の要素を追加する。(値型と参照型の違い)

「値型」と「参照型」

c#に限らず、プログラムをやると出てくる「値型」と「参照型」。

ややこしい部分であり、特に「参照型」はバグの原因になることも多いですので、実験結果も兼ねてメモ。

言い換えれば、こういうこと

僕が初学者の人に「値型と参照型の違い」について質問された時、下記の説明をします。

  • 値型(の代入):ファイルの「コピー&ペースト」
  • 参照型(の代入):ファイルの「ショートカットの作成」

前者の場合、元のファイルの内容をいくら変えようと、コピペ先のファイルの内容は変わりません。

でも後者の場合、作成元のファイルの内容を変えれば、ショートカットをダブルクリックして開いたファイルの内容も変わっています。

なので、上記の説明を借りると、

  • 値型:ファイルの「内容」(=値)をコピーする。
  • 参照型:ファイルの「リンク先」(=格納アドレス)をコピーする

と考えると、多少わかりやすいかも。

実際のコードで説明(クラスと構造体)

とはいえ「百聞は一見に如かず」なので、実験用のコードを下記に記載しました。 なおここでは、「似て非なるもの」としてよく例に出される、

  • クラス(=参照型)
  • 構造体(=値型)

を用いて説明します。
ちなみに、クラスと構造体の違いとしては、下記の通り。

処理 クラス 構造体
参照型 値型
フィールド宣言と同時に初期化 ×
引数無しコンストラクタの使用 ×
デストラクタの使用 ×
処理時間 遅い 速い

※「処理時間」に関しては、「大量のデータを処理した場合の速さの比較」なので、別に「クラスは一概に処理が遅い」わけではない。

参照:【C#】構造体の使い方

public partial class Form1 : Form
{
    struct PREF
    {
        public string pref1;
        public string pref2;
        public string pref3;
        public string pref4;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var prefs = new PREF();
        var list1 = new List<PREF>();
        var list2 = new List<List<PREF>>();

        prefs.pref1 = "愛知";
        prefs.pref2 = "岐阜";
        prefs.pref3 = "三重";
        prefs.pref4 = "静岡";

        list1.Add(prefs);
        list2.Add(list1);

        // 1

        prefs.pref1 = String.Empty;
        prefs.pref2 = String.Empty;
        prefs.pref3 = String.Empty;
        prefs.pref4 = String.Empty;

        // 2

        list1.Clear();

        // 3

        prefs.pref1 = "徳島";
        prefs.pref2 = "高知";
        prefs.pref3 = "愛媛";
        prefs.pref4 = "香川";

        list1.Add(prefs);

        // 4

        list2.Add(list1);

        // 5
    }
}

上記のコードの1~5の箇所で「list1」と[list2]のpref1~pref4の値をチェックすると、下記の違いがあります。

  • 1&2

    • list1
      • [0]
        • [pref1] = "愛知"
        • [pref2] = "岐阜"
        • [pref3] = "三重"
        • [pref4] = "静岡"
    • list2
      • [0]
        • [0]
          • [pref1] = "愛知"
          • [pref2] = "岐阜"
          • [pref3] = "三重"
          • [pref4] = "静岡"
  • 3

    • list1
      • 要素無し
    • list2
      • [0]
        • 要素無し
  • 4

    • list1
      • [0]
        • [pref1] = "徳島"
        • [pref2] = "高知"
        • [pref3] = "愛媛"
        • [pref4] = "香川"
    • list2
      • [0]
        • [0]
          • [pref1] = "徳島"
          • [pref2] = "高知"
          • [pref3] = "愛媛"
          • [pref4] = "香川"
  • 5

    • list1
      • [0]
        • [pref1] = "徳島"
        • [pref2] = "高知"
        • [pref3] = "愛媛"
        • [pref4] = "香川"
    • list2
      • [0]
        • [0]
          • [pref1] = "徳島"
          • [pref2] = "高知"
          • [pref3] = "愛媛"
          • [pref4] = "香川"
      • [1]
        • [0]
          • [pref1] = "徳島"
          • [pref2] = "高知"
          • [pref3] = "愛媛"
          • [pref4] = "香川"

動作の説明

  • 1:特に問題ないと思います。

  • 2:元の「prefs」の全フィールドの値を「String.Empty」にしていますが、prefsは(値型の)構造体なので、元のprefsが変更されても、list1の内容は変わりません。

  • 3:「list1.clear()」をしているので「list1」の要素はクリアされますが、list1は(参照型の)クラスなので、1の直前にlist1を追加した「list2」も、「list1」の変更の影響を受けます。 (ただし、list1自体が無くなったわけではないので、list1の参照自体は残っています。(=list2.Countの値は1のまま))

  • 4:ここが一番予想しにくい箇所。 「list1」に要素が変更されているのは当然ですが、「list2[0]」要素は「list1の参照先」なので、「list1」の要素が変更されれば、list2[0]の内容も直接影響を受けます。

  • 5:4でlist2[0]の要素が変更されましたが、list2.add()が実行されたので、list2[1]に新たにlist1の内容が追加されます。 結果、全く同じリスト(=list1)が2つ入っている、という結果になります。

と、参照型の代入は、想定外の動作をする場合があるので、気を付けないと、思わぬバグの原因になったりします。

回避策

簡単に言えば、「クラスの値のみコピーしたリストを追加する」処理を実施すればOKです。 やり方ですが、ソースのlist2.add(list1)の箇所を、

list2.add(new List<List<PREF>>(list1))

のように、

  • コンストラクタの引数に値コピー元のリストを設定して新規作成したたListクラス

を追加すれば、元のリスト(list1)の値が変更されようと、list2の内容は変わりません。

クラスと構造体の使い分け

最後になりますが、たまに参考書や一部のブログで、

迷ったら、クラスを使っておけば問題ない

という記載を見かけますが、何も考えずにクラスを使うと、上記のような思わぬバグを引き起こすので、要注意です。

個人的には、

  • クラス:色々な機能を付ける、拡張性を持たせる
  • 構造体:単に「値の受け皿」として使用する

として使い分けするのが良いかと思います。

以上、今回は長文になってしまいました。

Microsoftの「Sketch2Code」サービスを使ってみた感想

先日、Microsoftが「手書きの画面をHTMLに変換する」サービス「Sketch2Code」というサービスを発表しました。

www.atmarkit.co.jp


主にバックエンドがメインで、HTMLやCSSに触れる事が少ない僕としては、

  • Web系言語の勉強の際、UI(HTML/CSS)の作成に割く時間を減らせる
  • 業務の際、資料に書いた画面イメージからHTMLを作成できれば、かなりの時間を削減できる

のはかなりメリットだなと思ったので、期待を込めて、さっそく試してみました。


実用はまだ難しい...

で、試した結果が下記の画像。(簡単なフォーム画面)
左から順に

  • 作成した画面イメージ(Excelで作成)
  • 認識された構成
  • 自動生成されたHTML(の結果)

になります。

f:id:Makky12:20180909123601p:plain

と、結果としては、ちょっと残念な結果でした。
(手書きじゃないのがまずかったのかな?あるいは日本語認識が
まだ発展途上?)*1

先述のケースでHTMLの作成時間を減らせるのは、かなりメリットなのですが...*2
少なくとも、日本語をちゃんと認識できないと、業務で使用するのは難しいでしょうね。


これからに期待

とまあ、ちょっと実用は難しかったのですが、これから期待大なサービスであることは間違いないです。
Azureに力をかなり入れているマイクロソフトが開発しているのですから、品質もこれから改善されていくと思います。

それこそ先述のケース(特に業務)でHTMLの作成時間を軽減できれば、エンジニアの負担も減るのは間違いないですからね。*3


AIに仕事を取られる?

ただ、AIが色々出来るようになると、必ず話題になるのがこれ。

今はまだ問題ないでしょうが、今後技術がどんどん進歩すれば、「コーディングは全部AIにおまかせ」みたいになっていくんでしょうかね。

ただ個人的には、AIが進歩すれば、そのAIの品質向上のためにエンジニアが頑張る必要があるので、無くなる需要がある一方、下記のような、また別の需要が生まれると思います。

  • AIや機械学習分野に特化したプロフェッショナル
  • AIに関するロジック・業務分析など、コーディング以外の分野に特化したエンジニア


結局、求められるのは同じ
少なくとも(今でも言われている話ですが)、

  • 古い技術に対するこだわり
  • (古い体質・技術の)会社依存

を捨てられるか、そして

  • 時代にあった技術を習得・活用できるか

がエンジニアが求められるし、それは今も同じなんでしょうね。

*1:うまくHTMLを作成出来る画像のコツを知っていたら、どなたか教えて下さい...

*2:ただ、減ったら減ったでまた新しいタスクを入れるんでしょうね。これだから日本企業は...

*3:Excelの自動生成マクロからも解放される...のかな?

Githubにファイルをpushする際のトラブルシューティング

先日、フリーランス向けの「ふるさと納税可能額算出ツール」という
ツールをGithubに公開しました。

github.com

ただ、その際に色々ハマったことがありましたので、
備忘録も兼ねて対策方法を記載しておきます。


■SourceTreeが重いときの対処方法
Git操作系のGUIツールで有名な「SourceTree」ですが、このSourceTreeが
異常に重いことがあります。

SourceTree:https://ja.atlassian.com/software/sourcetree

「内蔵GitとシステムGitのバージョン差異」に起因する何かが
原因らしいですが、調べたところ、下記のような対処方法があるようです。

1. 一部ドライバを削除する

AMD Radeon graphics driver」というドライバを削除したり、
更新したら改善した、というケースがあるようです。
※もちろん、これやったから100%直る訳ではない。

Windows10 64bit でgitBashやSourceTreeがやたら遅い 重い


2. SourceTreeで「システムGitを使う」設定に変更する

SourceTreeの設定で「内蔵Gitを使う」設定になっている場合、
重くなるケースがあるようです。

その場合、
1. Gitの最新バージョンをインストールする。
2. SourceTreeの設定を「システムGitを使う」

とすると、改善する場合があるようです。(僕は直りませんでしたが...)

3. 諦めて、CUIベースで操作する

正直な話、これが一番確実な方法では?と思います。
Gitのコマンド自体はそんなに多いわけではないし、リポジトリ
クローンした後の基本的な、

  • ステージング
  • ローカルコミット
  • リモートpush

という作業だけなら、テンプレートのスクリプトファイルを作って、適宜
必要な箇所だけ修正し、そのスクリプトを実行すれば、毎回コマンドを入力する
手間も省けますし。

何より、無理にSourceTreeの調査に時間を充てるくらいなら、その方が
よっぽど時間を有効に使えるのでは?というのが最大の理由です。


■.gitignoreファイルが作成できない

.gitignore(管理しないファイルの設定ファイル)ファイルですが、普通に
Windowsエクスプローラ上で新規作成しようとしても、作成できません。
(「ファイル名を入力してください」とエラーになる。)
※「gitignore」を拡張子として認識してしまうため。


これを回避するには、

1. ファイル名を「.gitignore.」と入力して、新規ファイルを作成する。
(最後に「.」を付ける)
2. 「拡張子が付いていない...」というメッセージが表示されるので、
「はい」をクリックする。

これでエクスプローラ上でも「.gitignore」ファイルが作成できます。

というか、ファイル作成はGitHub上で行うのが無難かも。


■*.mdファイルのMarkdown記法がリモートリポジトリ上で効いてない場合の対処方法

ReadMeなどの*.mdファイルを更新した際、何故か途中から「Markdown記法が
全く反映されない」という現象が発生しました。

原因は、おそらく途中で設定ファイルの「改行コード」の設定を
手動で変えたことに起因する何か(内部コードがおかしくなった、等)だと
思われます。(ただ、Visual Studio CodeMarkdownビューアーでは、
全く問題なかったんですよね…)

これ自体の解決としては、単純に

  • Markdownが反映されない部分以前の空白文字を削除する
    (場合によっては書いた内容も)

で解決できますが、文字コードの設定は結構重要な部分なので、まとめました。

  • Github上で表示するファイル(*.mdファイルなど)は、改行コードは
    「LF」にする。
  • Gitのインストール時の改行コード設定に注意


f:id:Makky12:20180818073602p:plain

たいていインストールの設定って、デフォルトのまま「次へ」を連打して
しまいがちですが、(Gitは英語表記なのでなおさら)、
Gitの「改行設定」だけは注意が必要です。

上記画像では、上から順に

  • チェックアウト時はLF→CRLFに変換/push時はCRLF→LFに変換
  • チェックアウト時は変換なし/push時はCRLF→LFに変換
  • チェックアウト時/push時ともに変換なし

なんですが、真ん中の「チェックアウト時は変換なし/push時は
CRLF→LFに変換」にしておくのが、無難のようです。

気をつけて!Git for Windowsにおける改行コードqiita.com

※一番下の「変換無し」設定は、上記画像でもわかる通り、クロス
 プラットフォームの環境では非推奨なので、選ばないほうが無難かも。
※「変換無し」設定の場合、ツール側で設定などを行う必要があります。
 VS Codeなら「検索/置換」ウィンドウの「正規表現を使う」オプションを
 ONにすれば、改行コードでの検索/置換が可能です。
※ただ「変換あり」「変換無し」それぞれにメリット、デメリットがあり、
 一概にはどちらが良い、とも言えないようです。
qiita.com

以上、僕がGitHubにファイルをpushする際に遭遇したトラブル、および
その解決策でした。


てか、また前回からかなり間が開いてしまった...

業務都合だったり、あとメンタルの調子を崩したり、色々あったから
なのですが、やはりもう少し更新頻度を上げないと。
別に書きたいネタはそれなりにあるので、別にプログラミングのネタに
こだわらなくてもいいから、もう少し更新頻度を上げないといけませんね。
(こればっか)

【VBA】ファイルをクリップボードにコピーする(Win32API不使用)

超久しぶりの記事&超久しぶりにVBAの記事。
(てか、VBAって時点でネタ切れ感が…)

「(何かの)ファイルをクリップボードにコピーする」という場合の処理。
(要はファイルのコピー)

VBAクリップボードにコピー...という場合、よくあるのは「MSForms.DataObject」を使用する方法。

ただこれだと「テキスト」や「bitmap画像」はうまくいくけど「ファイルそのもの」のコピーはうまくいかない。
(VBAだから、Excel上でやり取りするデータ、という前提なのかも)

あと、Win32API関数を使用しても出来るけど、何個も関数を呼ぶ必要があるので、できればもっと単純にしたい。
(OpenClipboard()→EmptyClipboard()→SetClipboardData()→closeClipBoard()という流れ)

ということで、色々調べてたら、こんな感じで実装できた。
※簡略化のため、エラー処理とかはかなり端折ってます。
※dir_pathは対象ファイルの格納フォルダパス、file_nameはファイル名です。

Dim objShell As object
Dim objDir As object

Set objShell = CreateObject("Shell.Application")
Set objDir = objShell.Namespace(CVar(dir_path))
If (Not objDir Is Nothing) Then

    Dim objFile As object
    Set objFile = objDir.ParseName(file_name)

    For Each verb In objFile.Verbs
        If verb.Name = "コピー(&C)" Then
            verb.doit
            Exit For
       End If
    Next

    Set objFile = Nothing
End If

Set objDir = Nothing
Set objShell = Nothing

※参考:『ファイルをコピーしクリップボードに格納した状態』(田吾作) エクセル Excel [エクセルの学校]

処理の流れとしては

  1. Shell.Applicationオブジェクトを作成して
  2. 1のNameSpaceメソッドでFolderオブジェクト、またそのParseNameメソッドでFolderItemオブジェクトを取得して
  3. 2のVerbsコレクションからファイルのメニュー一覧を取得して「コピー(&C)」なら、それを実行する

という感じ。

ただ、2の「NameSpaceメソッド」で、フォルダパスをVariant型で渡さないとエラーになるので注意。
(まあ、公式ドキュメントにはちゃんと書いてあるけど...)

ただ、今回はコピーのみが必要だったから「貼り付け」の処理は実施してない。
機会があったら、調べてみようと思います。

てか、次はXamarinとかPythonとか、あとReact、Vue.js、Ionicなんかの触りの部分もやってみたいな。

【Xamarin.Forms】遭遇したエラーと対応集

Xamarin.Formsを触り始めてしばらく経ちますが、その中で僕が遭遇したエラー、及びその対処法になります。
なお、一般的なエラーについては、下記ページを参照。

※@nuits_jpさんのページ
Xamarin for Visual Studioインストール後、Androidプロジェクトをデバックしようとしたら配置エラーが発生した場合の対処法 - Qiita
Xamarin for Visual Studio スタートアップ トラブルQA集 - nuits.jp blog

※エクセルソフト 田淵さん(@ytabuchi)のページ
Xamarin FAQ(小技集、またの名をバッドノウハウ) - Xamarin 日本語情報

※僕がiPhone持ってないので、Androidのみ記載しています。すいません...


■ビルド時に「The $(TargetFrameworkVersion) for Xamarin.Forms.Platform.dll is greater than the $(TargetFrameworkVersion) for your project」というメッセージが表示される

【原因】
「ターゲットバージョン」で指定されているOSのバージョンが古すぎる。「ターゲットバージョン」は、最低限Xamarin.Forms.Platform.dllのOSのバージョンと同等かそれ以上である必要がある。

【対処方法】
[Androidマニフェスト]-[ターゲットAndroidバージョン]で、OSのバージョンを該当バージョンまで上げる。
※「SDKバージョンを使用した...」を選択している場合、[アプリケーション]-[Androidバージョンを使用したコンパイル]のOSバージョンを上げる。
デバッグで使用するデバイスのOSのバージョンが低い場合、「最小Androidバージョン」をそのデバイスに合わせればOK。


f:id:Makky12:20180422200239p:plain


■実行時に特定のメソッドで、NoSuchMethodErrorが発生する

【原因】
該当メソッドと、使用しているアセンブリ、またはデバイスのバージョン、及び互換性の問題。

【対処方法】
・使用しているアセンブリのバージョンが低い場合、Visual StudioAndroid SDK Managerなどで、最新バージョンに更新して、再度実行する。
デバッグに使用しているデバイスのOSバージョンが低い場合、更新できるなら更新する。(更新できない場合、別デバイスでの確認にする、あるいは該当メソッドのデバッグは諦めるしかない(かも))


■ビルド時に「前のバージョンの実行をサポートしていません。」というメッセージが表示される

【原因】
不明。
Visual Studioの更新を行った際に、何かの原因で発生することがある模様。

【対応方法】
ピンポイントでのベストな対応方法は不明。
今のところ「Visual Studioの修復or再インストール」しかないみたい...

【備考】
メッセージから「デバイスのOSを最新バージョンにすれば...」と思ってしまうが、最新バージョンにしてもこの現象は解決しない。(てか、ある程度前のバージョンは普通に動作するはずだし...)

参考ページ:Android - Xamarinのビルドに失敗。前のバージョンの実行をサポートしていません。(121632)|teratail


以上です。

【Xamarin.Forms】LabelにBorderを設定する

前回の記事同様、Style関連の内容です。

各種GUIで「Border(=境界線)」の太さや色などの設定、があると思います。
で、現在作成中のXamarin.Formsアプリで、同様の事をLabelで行おうとしたら...

Xamarin.FormsのLabelには「Border」プロパティがない!
※要は、枠線を表示できないということ。

まあ、ないものは仕方がないのですが、何とかやる方法はないか...ということで調べたら、以下の方法がありました。
参考:Xamarin.Forms で枠線付きのラベルを作る - clock-up-blog

1.LabelをFrame内に書く
→Frameの「OutlineColor」プロパティを使用すれば、枠線の色は指定できる。
 でも太さは指定できない。

2.Labelを2重Frameで囲む
→親Frameの「BackgroundColor」及び「Padding」を指定して、その中に子Frame&Labelを表示すれば、子Frame&Labelが表示されていない箇所が(見た目は)枠線のように表示される。
ただ、複数の枠線付きLabelを表示させたい場合、すべてに2重Frameを用意するのは、コーディングが面倒かも...

3.Buttonで代用する。
→Labelと違い、Buttonには「Border」関連のプロパティがあるので、それならButtonで代用しちゃえ、という方法。
 Labelへのこだわりがなければ、正直これが一番手っ取り早い。(ただ「Labelの枠線」という趣旨からは外れるけど...)
 
てか、なぜButtonにはBorderがあって、Labelにはないのか…


最後に、ソースコードと実際の画面をば。

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="ButtonRedStyle" TargetType="Button">
                <Setter Property="TextColor" Value="Black" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="Center" />
                <Setter Property="BackgroundColor" Value="Red" />
                <Setter Property="BorderColor" Value="Black" />
                <Setter Property="BorderWidth" Value="2" />
                <Setter Property="BorderRadius" Value="0" />
            </Style>
            <Style x:Key="FrameLabelStyle" TargetType="Label">
                <Setter Property="FontSize" Value="20" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout HeightRequest="500">
            <Label Text="1:LabelをFrame内に書く" />
            <Frame WidthRequest="110"
                HeightRequest="80"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Padding="0"
                OutlineColor="#f00" >

                <Label Text="あああ" Style="{StaticResource FrameLabelStyle}" TextColor="Black" />
            </Frame>

            <Label Text="2:Labelを2重Frameで囲む" />
            <Frame WidthRequest="106" 
                   HeightRequest="76" 
                   HorizontalOptions="Center" 
                   VerticalOptions="Center"
                   Padding="2"
                   BackgroundColor="#f00"
            >
                <Frame Padding="0"
                     BackgroundColor="#000"
                     VerticalOptions="Fill"
                     HorizontalOptions="Fill">
                    <Label Text="いいい" Style="{StaticResource FrameLabelStyle}" TextColor="Yellow" />
                </Frame>
            </Frame>

            <Label Text="3:Buttonで代用する" />
            <Button x:Name="button_red" Text="ううう" Style="{StaticResource ButtonRedStyle}" />
        </StackLayout>
    </ContentPage.Content>

f:id:Makky12:20180412212724j:plain

まだまだXamarinは発展途上、これからが楽しみですね。
(精一杯のフォロー)