satymale’s diary

日々の忘備録

Transbook T90Chiは意味もなくワクワクしてしまうサイズ

仕事で忙しくてあまり時間が取れないので、電車に乗っている時間を活用したらいいんじゃないかなと思って、約3万円という値段もあってTransbook T90Chi 3775をヨドバシカメラで買っちゃいました。 1週間程使ってみて、予想通りの使い方が出来て満足しています。

やっぱり8.9インチぐらいの大きさであれば、仕事の鞄に入れて持って行けるというのが一番大きいです。 キーボードを取り外した時のタブレットはもう壊れて使っていないNexus7を思い出します。 若干縦が長いようなタブレットの形状がNexus7に似てるなと感じます。

気軽にいつでもどこでも持ち出せるこのサイズで、Visual Studioが動くというのは本当に嬉しいです。 意味もなくワクワクしてしまいます。

電子ノート、XPS13との比較

f:id:satymale:20160124231028j:plain

XPS13もずいぶん薄くてコンパクトなノートPCですが、仕事鞄に入れたり電車で作業をするにはちょっと存在感がありすぎてしまいます。8.9インチだとあまり仕事してる雰囲気でなくて良いです。

f:id:satymale:20160124232652j:plain

キーボード込みの16.5mmで鞄に入れる分には問題ないですが、欲を言えば2in1でなくていいので、クラムシェル型でもっと薄くしてくれたら嬉しかったです。

T90Chiの側面

f:id:satymale:20160124231407j:plain

このラインがあると質感良く感じます。 他は少しチープな印象を受けますが、気軽に鞄にいれて持ち出すので傷がつくのが躊躇われるぐらいの質感になると、それはそれで神経使って困るのでこれくらいでいいかなと思います。

速度比較

Visual Studio Community 2015を起動すると、T90Chiは約8秒ぐらいで起動します。 Core i5のXPS13では約2秒ぐらいで起動します。 SourceTreeではT90Chiは約9秒、XPS13は約4秒ぐらいなので、アイコンをタップした後は焦って再タップせずにちょっと待つことが必要です。

イシューログ

タップしづらい

キーボードにトラックパッドがついていないので、画面を直接タップして選択するしかないのですが、表示によっては細かくてタップがしづらい時があるので、タッチパネルでマウス操作が行えるToushMousePointerというソフトを入れています。

TouchMousePointer タッチパネルをタッチパッド化

【2016.03.05 追記】また極力キーボードだけで完結できるように、SendToフォルダに エディタ等のショートカットを入れておくことで、batファイルの編集など右クリックキーから簡単に行えるようにしています。

画面が真っ黒で反応がない

たまに電源ボタンを押してもバックライトだけついて画面が真っ黒になる時があります。 何をするとそうなるのかまだ因果関係はわかりませんが、この事象に遭遇したら電源ボタンをかなり長く押して強制的に再起動を行うと治ります。

【2016.03.03 追記】上記の事象が発生した時、Ctl+Alt+Delを押すとログイン画面が表示されました。

タスクバーがタップしづらい

キーボードとタブレットの接続部分付近は指先が細い人は良いのですが、タスクバーにピン止めしているアプリケーションを起動しにくいです。

タスクバーのアプリケーションを選択できるショートカット[Winキー + T]を覚えておく便利です。

プレリリースソフトウェアのライセンスが切れていますと出る場合

Visual Studio Community 2015をインストールしたら、「プレリリースソフトウェアのライセンスが切れています」と出て開けない事象に遭遇しました。 その時は、Visual Studio Community 2015を修復でインストールすると良くなりました。

ASP.NET4.6+W2UIでデータを保存する

サーバー側で変更分が分からない問題

W2UIで入力されたデータを保存すると、変更があった差分のみがサーバーに渡されます。 例えば次のようなGridのlnameとsdateを編集して保存すると

$('#grid').w2grid({
    name : 'grid',
    url  : {
        get    : 'server/side/path/to/records',
        remove : 'server/side/path/to/remove',
        save   : 'server/side/path/to/save'
    },
    columns: [                
        { field: 'recid', caption: 'ID', size: '50px' },
        { field: 'lname', caption: 'Last Name', size: '30%' },
        { field: 'fname', caption: 'First Name', size: '30%' },
        { field: 'email', caption: 'Email', size: '40%' },
        { field: 'sdate', caption: 'Start Date', size: '120px' },
        { field: 'edate', caption: 'End Date', size: '120px' }
    ]
});

次のように変更分のみサーバーに送信されます。

cmd:save-records
selected[]:1
limit:100
offset:0
changes[0][recid]:1
changes[0][lname]:hoge
changes[0][sdate]:2016/01/23

サーバー側のコントローラーでは次のように、パラメータの型に動的にマッピングされるため変更されたプロパティにしか値が設定されません。

public class GridSaveParameter<T> {
    public string Cmd { get; set; }
    public int[] Selected { get; set; }
    public int Limit { get; set; }
    public int Offset { get; set; }
    public List<T> Changes { get; set; }
}

public class Hoge {
    public string Recid { get; set; }
    public string Lname { get; set; }
    public string Fmame { get; set; }
    public string Email { get; set; }
    public DateTime Sdate { get; set; }
    public DateTime Edate { get; set; }
}

public ActionResult Save(GridSaveParameter<Hoge> param) {
    // 保存処理
}

そうなると、保存する際に値なしに変更されたのか、変更されていないのかを判断することが出来なくなります。

すべての値を送る

上記のように、変更分のみをサーバー側に送信すると、値を空にした場合が判断できなくなるため、 クライアント側で、変更があった行のすべての値をサーバー側に送るように少し手を加えます。 urlの指定からsaveを消して、保存ボタン押下時のイベントで自前で値をサーバー側に送信します。

$('#grid').w2grid({
    name : 'grid',
    url  : {
        get    : 'server/side/path/to/records',
        remove : 'server/side/path/to/remove',
    },
    columns: [                
        { field: 'recid', caption: 'ID', size: '50px' },
        { field: 'lname', caption: 'Last Name', size: '30%' },
        { field: 'fname', caption: 'First Name', size: '30%' },
        { field: 'email', caption: 'Email', size: '40%' },
        { field: 'sdate', caption: 'Start Date', size: '120px' },
        { field: 'sdate', caption: 'End Date', size: '120px' }
    ],
    onSubmit: function (event) {
        // 2016.08.07 追記
        // url.saveを消すことで、保存した際に、サーバからのstatusがerrorか否かに関わらず
        // 編集箇所がクリアされる分岐に入ります。
        // そのため、既定の保存処理を中断しておきます。
        event.isCancelled = true;

        var chgRows = w2ui['grid'].getChanges();
        
        // 変更があった行の変更前のすべての値を持った行に変更された値を上書き
        var rows = $.map(chgRows, function (n, i) {
            return $.extend(w2ui['grid'].get(n.recid), n);
        });
        
        w2ui['grid'].request('save-records', { changes: rows }, 'server/side/path/to/save');
    }
});

上記のようにすると値が空の場合は素直に空になって送信されるので、サーバー側では特に考慮することなく保存すれば良くなります。

電子ノートは仕事で使えるのか

紙ノートの不満点

私は仕事でキャンパスノートを愛用しています。

学生の頃からノートは使っていたけど、シャープペンシルを使うと手が汚れるし、ボールペンを使えば間違った時に消せないという不満点があって、そんなに積極的にノートを使う方ではなかったのですが、擦ると熱で消せるフリクションボールペンが登場して以来、ノートは頭の整理やメモ等になくてはならないものになってきました。

ただノートを積極的に使うようになってまた別の問題が生まれるようになってしまいました。 A4ノートを20日で使い切ってしまい、外出先でノートにメモしてた内容を見ようとしたら1つ前のノートに書いていて「しまった!」というような事が起きるのです。 フリクションボールペンも4色タイプを使っているのですが、すぐインクがなくなってしまいます。 そのため、それぞれの色を2袋(6本)は常に常備しておき、筆箱には1本ずつ入れてインク切れに備えなくてはなりません。

スケジュールは手帳が便利

加えて仕事の内容が開発からシステム構築SEに変わったため、スケジュール管理の比重が高くなってきており、手帳も持ち歩いています。 やっぱりノートに予定を書き込むよりは、カレンダーに予定を書き込む手帳の方が予定の順序関係が分かりやすくて便利です。 ただある程度ストレスなく手帳を使おうと思うとそれなりに大きい手帳が必要になってきます。 そうなるとそこそこ大きい手帳と、ノートの両方を持たなくてはならず荷物が多くなってしまいます。

電子手帳の導入

何冊ものノートを持ち運べて、インク切れを心配することなく、スケジュールの書き込みが出来るものという事で、電子ノートを購入しました。 一番私の求めるものに近そうなシャープのWG-S30を購入です。

シャープ 電子ノート ブラウン系 WG-S30-T

シャープ 電子ノート ブラウン系 WG-S30-T

電子ノートでの一番の不安はやはり書き味につきます。 電話を受けながらメモを取れるレベルの追従性がないといくら持ち運びが良くなっても使いものにはなりません。

不安を抱きつつも買った次の日に実際に職場に持っていき運用してみた所、細かい文字を書こうとするとキツイですが1cm×1cm四方ぐらいであれば問題ありませんでした。

画面が見づらい

ただ、このシャープの電子ノートは書き味よりもとにかく画面が透過型液晶ではなく反射型白黒液晶のため見づらいです。 バックライトがないので、電池持ちは30日とほとんどバッテリーを意識することなく使えるので良いですが、初代ゲームボーイみたいな感じの画面です。 天井のライトが反射すると見づらいので、反射低減の保護フィルムを一緒に用意することをお勧めします。

タッチペンも感圧式なので、iPadタッチペンというよりはNintendo DSのような書き心地で、タッチペンをあてるとペコペコしたような感触がします。 タブレットタッチペンで同じ運用は出来ると思いますが、やはりスケジュール帳とノートに特化しているため余計な機能がついていない分、書くことに集中できる点が良いです。

今の電子ノートは仕事で使える

電話を受けるときのメモも問題なし、スケジュールの記入も問題なし、ノートもA4ノートよりは狭いですがページを次々と作れるため 今のところ問題なく仕事で使えています。 また、ノートを自由に作れる上、それぞれのノートからページをコピーできるので、ノウハウ集みたいなものを簡単に作れるのがとても良いです。 紙ノートだと、同じものを作る場合は転記が必要になってしまいとても面倒です。

だいぶ便利な電子ノートですが、次に新型が出るならKindle Paper Whiteのようなe-Inkの画面ともっと書くことに特化するため、カバーを開けたらすぐ書けるようにしてくれることを希望したいです。


satymale.hatenablog.com

設定ファイルの値を取得する

設定ファイルの内容をControllerで使う方法が分からなかったので調べてみました。

config.json

{
    "Data": {
        "DefaultConnection": {
            "ConnectionString": "test"
        }
    }
}

Startup.cs

public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) {

   var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
       .AddJsonFile("config.json")
       .AddJsonFile($"config.{env.EnvironmentName}.json", optional: true);

    builder.AddEnvironmentVariables();
    Configuration = builder.Build();
}

public IConfiguration Configuration { get; set; }

// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services) {
    services.AddMvc();
    services.Configure<Config>(Configuration);
}

Config.cs

public class Config {
    public Data Data { get; set; }
}

Data.cs

public class Data {
    public DefaultConnection DefaultConnection { get; set; }
}

DefaultConnection.cs

public class DefaultConnection {
    public string ConnectionString { get; set; }
}

HomeController.cs

public class HomeController : Controller {

    private Config _config;

    public HomeController(IOptions<Config> config) {
        _config = config.Options;
    }
}

ASP.NET5 + EntityFramework6でSQL Server Compact Editionを使う。

EntityFrameworkはCode FirstモードというコードからDBのテーブルを作る機能があるらしいですがまだそれは勉強していないので、先にテーブルを作ってEntityFrameworkから利用する方法を忘備録がてら残します。(2日ぐらいこれではまったので・・・)

NuGetでSQLServerCEのEntityFrameworkをインストールする

プロジェクトのリファレンスフォルダで右クリックをし、「NuGet パッケージの管理」をクリックします。 開かれたパッケージマネージャで「EntityFramework.SqlServerCompact」をインストールします。 f:id:satymale:20151105213529p:plain

DBを用意する

SQL ServerCEのDBであるsdfファイルを作成します。 昔はプロジェクトからファイルの追加で作れていた記憶があるのですが、ASP.NETのプロジェクトにはsdfファイルが存在しないので、SQL Serever Compact/SQLite ToolboxをVisual Studioにインストールします。

visualstudiogallery.msdn.microsoft.com

インストールが終わったら、SQL Server Compact/SQLite Toolboxからsdfファイルを作っていきます。

Data Connectionから右クリックを行い、「Add SQL Server Compact 4.0 Connection」をクリックします。 f:id:satymale:20151105120959p:plain

「Create」ボタンをクリックし、sdfファイル名を入力してから「OK」ボタンをクリックします。 f:id:satymale:20151105121600p:plain

テーブルを用意する

無事sdfファイルが作成されたら、テーブルを作っていきます。 sdfファイルにTablesがあるので、右クリックをして「Build Table」を選択します。

f:id:satymale:20151105122224p:plain

テーブル名や列を設定し、「Script!」ボタンをクリックします。 f:id:satymale:20151105122502p:plain

すると、SQLが生成されるので、「F5」ボタンか、赤枠で囲われたボタンをクリックします。 f:id:satymale:20151105122707p:plain

データを用意する

後でコードからテーブルの内容が取得できているか確認するために、データを用意しておきます。 テーブルで右クリックし、「Edit Top 200 Rows」をクリックします。 f:id:satymale:20151105123106p:plain

データを入力して「save」ボタンをクリックします。 f:id:satymale:20151105123636p:plain

コードを作成する

テーブルの準備ができたので、コードを作っていきます。 先ほど作成したテーブルを表すクラスを作ります。

using System.ComponentModel.DataAnnotations.Schema;

[Table("Hoge")]
public partial class Hoge {
    public int Id { get; set; }
    public string Col { get; set; }
}

Configurationを作成する

次にConfigurationを作ります。 このConfigurationは、後で作るコンテキストに渡す接続文字列がどのDB向けなのかを表すためのクラスになります。 これがないとデフォルトでSystem.Data.SqlClientが使用されます。

詳しくは以下に記載されています。 msdn.microsoft.com

これを私は知らなかったので、SQL Server CEの接続文字列を渡しても、Initial Catalogが指定されていないといったエラーメッセージが表示され四苦八苦してました。

using System.Data.Entity;
using System.Data.Entity.SqlServerCompact;

public class SqlserverCeConfiguration : DbConfiguration {
    public SqlserverCeConfiguration() {
        SetProviderServices(SqlCeProviderServices.ProviderInvariantName, SqlCeProviderServices.Instance);
    }
}

コンテキストを作ります。

using System.Data.Entity;

[DbConfigurationType(typeof(SqlserverCeConfiguration))]
public class HogeContext : DbContext {

    public HogeContext(string connectionString) : base(connectionString) {
    }

    public IDbSet<Hoge> Hoge { get; set; }
}

DNX Core 5.0を対象外にする

ビルドを行うと、DNX Core 5.0でEntityFramework.SqlServerCompact関連のアセンブリがない等のエラーが出ます。 f:id:satymale:20151105222016p:plain

Windows以外の環境で動かす予定はないので、DNX Core 5.0をproject.jsonから削除します。

"frameworks": {
    "dnx451": { },
    "dnxcore50": { }
},

"frameworks": {
    "dnx451": { }
},

値を取得する

実際にHogeテーブルに入っている値が取得できるか試してみましょう。

public IActionResult Index() {
    var context = new HogeContext(@"Data Source='D:\test.sdf';");
    var row = context.Hoge.FirstOrDefault();
    
    return View();
}

無事、値が取れましたね! f:id:satymale:20151105222152p:plain

Excelのシートを比較

最近Excelをよく使うようになって、シートの値の比較を効率よく出来るようになりました。

前は以下のようにIF文を使って差異を見つけていましたが

=IF(Sheet1!A1=Sheet2!A1,"○", "×")

Sheet1の条件付き書式で以下のようにやれば色も同時に付けれて一石二鳥です。

=INDIRECT("Sheet2!" & ADDRESS(ROW(), COLUMN())) <> A1

w2ui.loadにrecordsのJSONを返すURLを指定してはいけない

w2ui['グリッドのname'].load('JSONを返すURL');

上記のコードでサーバからデータを取得してグリッドに表示するが、データは以下の構造が正しい。

{
    "status" : "success",
    "total" : 1,
    "records" : [{
        "recid" : 1,
        "hoge" : "ほげ"
    }]
}

グリッドに直接指定していたrecords部分をloadでサーバから取ってくるものだと勘違いしていたため、以下のデータを返していて何も表示されなくて悩んでいた。

[{
    "recid" : 1,
    "hoge" : "ほげ"
}]

同じように勘違いする人がやはり居るらしく、w2uiの本家サイトに同じ質問がされていて回答が載っていて私も勘違いに気づいた。