iOS用の社内ライブラリ

iPhone用アプリの開発でWindows用社内ライブラリに入っているクラスを使うことになり、せっかくなのでiOS用社内ライブラリを作成しました。

以前UWP用社内ライブラリを作成したときに共通化できそうなソースコードは共有プロジェクトに移動したので、今回は簡単にiOS用社内ライブラリが出来上がりました。
Xamarinの互換性の高さに驚きです。

WindowsFormsのコントロールの背景色やフォントが設定されているかを取得

最近、WindowsFormsのコントロールの背景色やフォントが設定されているかを取得する必要があったので、Controlについて調べてみました。
なお、背景色やフォントは親コントロールから継承されるので、普通にBackColorプロパティやFontプロパティでは設定されているかを調べられません。

以下のサイトでControlのソースコードを調べました。
Reference Source

結果、internalなRawBackColorプロパティとIsFontSetメソッドをリフレクションで実行すれば取得できそうです。

実装は以下のようになります。


public static class ControlExtension {
    private static Func RawBackColorDelegate { get; }
    private static Func IsFontSetDelegate { get; }

    static ControlExtension() {
        RawBackColorDelegate = typeof(Control).CreateGetPropertyDelegate<Func>("RawBackColor", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
        IsFontSetDelegate = typeof(Control).CreateMethodDelegate<Func>("IsFontSet", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod);
    }

    public static Color RawBackColor(this Control ctl) {
        return RawBackColorDelegate(ctl);
    }

    public static bool IsFontSet(this Control ctl) {
        return IsFontSetDelegate(ctl);
    }
}

public static class TypeExtension {
    public static TDelegate CreateGetPropertyDelegate<TDelegate>(this Type type, string name, BindingFlags flags) {
        var property = type.GetProperty(name, flags);
        var info = property.GetGetMethod(flags.HasFlag(BindingFlags.NonPublic));
        return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), info);
    }

    public static TDelegate CreateMethodDelegate<TDelegate>(this Type type, string name, BindingFlags flags) {
        var info = type.GetMethod(name, flags);
        return (TDelegate)(object)Delegate.CreateDelegate(typeof(TDelegate), info);
    }
}

Controlの拡張メソッドにしましたので、全てのコントロールで使用可能です。
毎回リフレクションは遅いので、staticコンストラクタであらかじめデリゲートを作成しています。
ついでに、Delegate.CreateDelegateメソッドをラップする拡張メソッドも作成しました。

スプリッタコントロール

今月はC#のSplitterコントロールとSplitContainerコントロールの2つのスプリッタコントロールに機能追加を行いました。

スプリッタコントロールは以下の画面のように、2つの領域をマウス操作で可変にするコントロールです。
なお、この画面は弊社で作成している社内用の画像処理ソフトです。

追加したのは以下の機能
1.マウスオーバー時に色を変更する処理
2.ダブルクリックで一方の領域を最小化したり元のサイズに戻したりする処理

この機能追加を社内ライブラリにおこないましたので、今後のアプリではこの機能が簡単に使用できるようになります。

今回対応したのはWindowsFormsだけなので、いずれWPF用にも対応を行う予定です。

Xamarin.Formsを使用してWindowsデスクトップアプリ開発

モバイル用のクロスプラットフォームUIツールキットのXamarin.Formsですが、Windowsデスクトップアプリにも使えるようになるそうです。今後使うかも知れないのでとりあえずメモ。

https://qiita.com/tan-y/items/cf5088c6853ebb1b6c64
https://qiita.com/tan-y/items/e08d297c2d013214eb83

C#のZip拡張メソッド

以前にブログに記載しました、C#7で追加された分解の機能に関係するお話。

この分解が増えたことで、LINQのZip拡張メソッドをもっと使いやすくできるのではなかろうかと思い、新しいZip拡張メソッドを作成してみました。

まず、いままでのZip拡張メソッドの例。


var xArray = new[] { 1.1, 2.2, 3.3 };
var yArray = new[] { 4.4, 5.5, 6.6 };
foreach (var item in xArray.Zip(yArray, (x, y) => new { x, y })) {
    Console.WriteLine($"X={item.x} , Y={item.y}");
}

xArrayとyArrayをマージして新しい匿名クラスを作成しています。
匿名クラスを作成するラムダ式を指定するのが面倒ですね。

で、新しく追加したZip拡張メソッドを使用すると以下のようになります。


var xArray = new[] { 1.1, 2.2, 3.3 };
var yArray = new[] { 4.4, 5.5, 6.6 };
foreach (var (x, y) in xArray.Zip(yArray)) {
    Console.WriteLine($"X={x} , Y={y}");
}

匿名クラスを使用せず、Tupleクラスのインスタンスを返すようにしました。
C#7で増えたタプルではなく、昔からあるTupleクラスなので、通常ならば値にアクセスする場合、item.Item1やitem.Item2などのようにxやyの名称がなくなり可視性が悪いですが、分解のお陰で、xとyの名称そのままで値にアクセスできるようになりました。

ちなみに、新しく作成したZip拡張メソッドの実装は以下となります。


public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(this IEnumerable<T1> items1, IEnumerable<T2> items2) {
    return items1.Zip(items2, (item1, item2) => Tuple.Create(item1, item2));
}

同じようにして、3つのシーケンスをマージするメソッド、4つのシーケンスをマージするメソッドと、いくつか作成しておくと便利です。

Windowsのネットワーク接続の設定

1ヶ月位前からWindowsタブレットのバッテリ消費が早いので何かおかしいと思っていたが原因が判明。

以下のネットワーク接続の設定が「なし」になっているのを「常時」に変更することで改善。
間違って変えてしまったのかWindowsアップデートで変わったのか分からないですが、一安心です。

それにしても、「なし」と「常時」の意味がわかりにくい。
なし:スリープ時のネットワーク切断を行わない。
常時:スリープ時のネットワーク切断を常に行う。
もうひとつ「Windowsで管理」という項目もあり、Windowsがなんかうまく制御してくれるものと思われます。

C#のタプルと分解

C#7で追加されたタプルのフィールドを分解する構文について、タプル専用の機能ではなくユーザ定義の型でも分解が行えると知ったので試してみました。

タプルのフィールドを分解する構文は以下のようになります。


var t = (Value1: 2, Value2: 3D);
var(v1, v2) = t;

1行目で2つのフィールドを保持するタプル変数tを作成し、
2行目で変数tのフィールドをv1とv2に分解しています。

これだけでは意味が無いですが、メソッドの戻り値はタプルで返し、
メソッド実行側はすぐに分解して使用したい場合などに役立ちます。

上記の分解と同様のことを行うには、クラスや構造体にDeconstructメソッドを実装します。拡張メソッドでもOKです。
KeyValuePair構造体のDeconstruct拡張メソッド実装例は以下のようになります。


public static void Deconstruct<TKey, TValue>(this KeyValuePair<TKey, TValue> pair, out TKey key, out TValue value) {
    key = pair.Key;
    value = pair.Value;
}

例えば、Dictionaryの各要素をforeachで処理する場合、今まであれば以下のようになります。


var dic = new Dictionary<string, int>();
foreach (var pair in dic) {
    Console.WriteLine(pair.Key + "=" + pair.Value);
}

Deconstruct拡張メソッドを実装して分解が行えるようになると、以下のような実装が可能になります。


var dic = new Dictionary<string, int>();
foreach (var (name, score) in dic) {
    Console.WriteLine(name + "=" + score);
}

変数pairを使用する必要がなくなり、pair.Keyとpair.Valueではなく、本来のフィールドの意味を表す変数名を名付けて利用できるようになりました。

 

Visual Studio 2017 がフリーズ

先週くらいからVisual Studio 2017 が良くフリーズして再起動するようになり困っていました。

最近の環境変更で考えられるのは、Version15.4.3になったことと、Xamarin関係をインストールしたこと。

Visual Studio自体や拡張機能の更新も全て行っており、問題はないはず。

なんとなくReSharperが怪しいのではと思い、JetBreinsのサイトを見てみると、現在使用しているのよりも新しいReShaperがある。拡張機能の更新プログラムに何故表示されないのかは分からないが、ダウンロードしてインストールしてみると、フリーズがなくなったみたい。とりあえずは解決です。

ログビューワソフト

社内用にログビューワソフトを作成しました。

弊社が作成するPCソフトは必ずログファイル出力を行えるようにし、何らかの問題が発生した時にお客様の工場などに行かなくてもログファイルを調査することで大概のことは解決できるようにしています。

ログファイルは単なるテキストファイルなので、今まではテキストエディタを使用して調査を行っていましたが、専用のビューワソフトを作成したほうが効率が良いのではなかろうかと考え、社内用に作成してみました。

今ある機能は、ログ内容に応じた色分け表示、正規表現検索、検索結果の一覧表示、複数ファイルの一括表示、選択行からの相対時間表示など。

今はまだ機能が多くないのですが、これから必要に応じて機能追加をしていくつもりです。

UWP対応

先日、ラズペリーパイ3 + Windows 10 IoT Core の案件があり、せっかくなのでいつも使用している社内ライブラリのUWP(ユニバーサル Windows プラットフォーム)版を作成しました。

共通化できそうなソースコードは共有プロジェクトに移動した結果、UI関係やWindows依存な箇所以外はほぼ共通化が出来ました。単体テストも共通化出来ましたので動作確認もスムーズでした。

これで今後のUWP案件で効率良く開発できる準備が整いました。