読者です 読者をやめる 読者になる 読者になる

Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

業務系アプリでWPFを使うメリットがなかった件

C# winform WPF

非常によくわかるお話だった。特にここ。

kiwosuke.hatenablog.com

MVVMの原則に従って一生懸命、コードビハインドからコードを追い出したところでほとんどメリットが感じられません。

業務系のアプリはデスクトップのテンキーをベースに操作ができることを求められるから、キー関連のイベントを拾わざるをえなくなり、結局コードビハインドは追い出せない。ボタンをクリックするの?Enterで検索開始すればいいじゃない、とかさ。

MVVMをやる時に一番困るのがコードビハインドからViewModelに処理を投げてそのViewModelからUIにメッセージを返すところ。ココがよくわからなかった。WPFのMVVMは敷居が高く、オレオレ実装でやると予期せぬバグを生み出す温床になります。同じデータなのにAさんとBさんで表示結果が1個のセルだけ違うというバグが...

WPFはWindowsFormの感覚で作ると火傷するということです。全く別物と考えていいでしょう。あと、画面がどうしても重たい。UIを仮想化している為だと思うがUserControlに色々コンポーネントを付け足していくスタイルだと仮想化されたUIが更に重くなる(JSでいうDOMみたいなやつ)みたいで、画面の描画がロースペックなマシンだと時間がかかる。これをチューニングするとなると、作り方を大きく変えないといけない。

WPFの利点にコントロールの外観を自由に変更できることがある。同じデータを円グラフとテーブルの表で表示する、なんてことは大得意。でも、そのメリットを享受できるケースは業務系のアプリにおいてとても限られている。

振り返ってみるとWPFの一番のメリットは画面サイズが固定でなくても良い所と、依存関係プロパティ、データバインディングの3つだった気がした。

WPFは画面サイズやウインドウサイズに応じて自動的に画面の再描画が走るので、相対配置に対応している。Windowsフォームは原則サイズ固定だけど、下記のやり方を使えばフレキシブルにできるみたい。

www.wisdomsoft.jp

依存関係プロパティってのは、CSSのように html { font-size:20px;} って指定すると、全てのfont-sizeプロパティを持つUI(p,span,td...など)に変更が伝搬される仕組みのこと。Styleとコントロールは完全に独立されている設計だから。Windowsフォームでは出来なかった。やるとすれば親Formで再帰でループ回してfontsizeプロパティを持ってるなら変更する感じになるかな。別にこれじゃなくてもええけど、他にやり方を知らない。

データバインディングについてはWindowsフォームでも出来る。コードビハインドで画面のViewを内包したモデルを作ってインスタンス作ればいいだけ。多分オブジェクトのネストにも対応してくれるだろう。

WindowsFormsでの単項データバインドまわり | tocsworld

結局、Windowsフォームでもやりたいことはできるし、画面のコンポーネントがダサいというか古臭い所はあるだろうけど、WPFより操作は簡単で作りやすい。デスクトップアプリはWebアプリの3倍難しいのが僕の肌感。Web上に乗っかってるサンプルコードをちょいちょいで見様見真似で....っていうのは困難。GUIのハンドリングは実にめんどくさい。高い操作性を得るためなら、クライアントに配るライセンスがフリーのツールを買うのが最も正しい選択だなと、3ヶ月WPFをどっぷりやっておもいました。

おわり。

WPFのXPSDocumentの横向き印字

C# WPF

Programmer's Report: WPF で横長(Landscape)印刷をするを参考にしつつ。

こんなコードで横向き出来ました。

var printQueue = new LocalPrintServer().GetPrintQueue(
    "YOUR PRINTER NAME");

PrintTicket ticket = printQueue.DefaultPrintTicket;
ticket.PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4);
ticket.PageOrientation = PageOrientation.Landscape;
var xpsDocWriter = PrintQueue.CreateXpsDocumentWriter(printQueue);

FixedDocument fixedDoc = new FixedDocument();

for (int i = 1; i <= invoice.totalPage; i++)
{
    var fixedPage = new FixedPage();
    fixedPage.Width = 11.69 * 96;
    fixedPage.Height = 8.27 * 96;
    var pageContent = new PageContent();
    fixedPage.Children.Add(new MyUserControl());
    ((IAddChild)pageContent).AddChild(fixedPage);
    fixedDoc.Pages.Add(pageContent);

}
xpsDocWriter.Write(fixedDoc, ticket);
  • PrintTicketで横向きにする
  • サイズを決め打ちでfixedPageに与える。
  • XPSに書き込む時に、引数にTicketを与えておく。

以上です。

C#でプリンタの接続ステータスを拾う

C#

こんな感じで拾えますので、どぞ。System.ManagementのDLLに参照を追加してImportしておいて下さい。

public static bool IsPrinterOffLine(string printerName = "")
{
    ManagementScope scope = new ManagementScope("\\root\\cimv2");
    scope.Connect();

    // Select Printers from WMI Object Collections
    ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");
    foreach (ManagementObject printer in searcher.Get())
    {
       if(printer.GetPropertyValue("DeviceID").Equals(printerName)) {
           return (Boolean)printer.GetPropertyValue("WorkOffline");
       }
    }
    //プリンタが見つからないならtrue
    return true;
}

Windowsアプリの自動テストはFriendlyが良さげ

winform WPF

WPFでデスクトップアプリを作りまして、画面操作のテストが非常にめんどくさい。Seleniumに該当するものが無いかを簡単に調べてみた。大きく分けてこの3つがあるようだ。

  1. UIAutomation
  2. Winium
  3. Friendly

UIAutomationというのはMSが標準で用意している画面操作のテストライブラリ。VisualStudioを起動して、そこにテストコードを書いていく。WiniumはSeleniumにインスパイアされたWindowsのデスクトップアプリを操作するライブラリで、UIAutomationのラッパーライブラリのようだ。どっちを使っても大差は無さそう。FindByXXXの呪縛からは逃れられない。

github.com

で、もう1つの選択肢がこちらのFriendly。

www.codeer.co.jp

対象プロセス(端的に言えばテスト対象のアプリのexe)を別のプロセスから操作することができ、対象プロセスが保有するすべての属性や関数にアクセスすることが出来る。なぬ? FindByXXが不要でUIテストのコードが書けるってこと?!それはしゅごい。それだけで心が動く。

APIを詳しく見ていないのですが、僕はXAMLに全然ElementNameを書いていない。MVVMではそんなもの原則不要。ボタンは全部ViewModelのコマンドにバインドしているので、バインドされているViewModelのコマンドをUIテストコードで直接キックできれば楽にテストが書ける...

え?出来ちゃうの?バインドしてるコマンドでボタンを特定してキック出来るっぽいコードが書いてある。なにそれすごい。

ishikawa-tatsuya.hatenablog.com

var app = new WindowsAppFriend(Process.Start("Target.exe"));
WindowControl main = WindowControl.FromZTop(app);

//ApplicationCommands.Closeの割り当たっているボタンを特定
var buttonClose = main.LogicalTree().ByType<Button>().ByCommand(ApplicationCommands.Close).Single();

・・・GWの連休課題で試しに動かしてみたいと思います!

営業事務(マーケ担当)はSQLを覚えるべきだし、2時間で覚えられる。

Sql

qiita.com

めっちゃええ話。これはすごく意味がある。細かいツッコミをすれば、上記はSQLを簡単に投げられるようになった話でありSQLを駆使できるようになったわけではないのだけど、そのうち覚えるやろ。

弊社では商品企画を担当する社員がおりまして、ExcelでVLOOKUPはできるけどデータベースの操作はしたことがない、というレベルです。僕が隣でSQLを書いているのを見て、「これなら出来そうだから教えて」と言われたので、教えました。2時間の講習でここまで覚えてくれました。

  • データベースとテーブルの関係
  • SELECT,FROM,WHERE,LIKE,ORDER BY
  • JOIN,GROUP BY,CASE-WHEN
  • 簡単なDB関数

なので、「エプロンという品名の商材を抽出して、伝票日付が4月と5月の売上の2013年以降の年度別の対比が見たい」というSQLが書けるようになりました。具体的にはこんな感じです。

select
  year(e.billdate) as yearly,
  sum(case 
     	when month(e.billdate) = 4 then ed.ordernum
     	else 0
  	end) as 4月,
  sum(case 
     	when month(e.billdate) = 5 then ed.ordernum
     	else 0
  	end) as 5from
  earning_details as ed 
  join items as i on i.id = ed.item_id
  join earnings as e on e.id = ed.earning_id
where
 e.billdate >= 2013
and 
 i.name like '%エプロン%'
group by
  yearly

微妙に構文が違ったりすることはあるんですが、その辺はどうとでもなります。やってる内容がわかれば。

以下、説明に使ったナイストーク集です。

データベース is 何

Excelで例えました。データベースはブック、テーブルはシート。シートに名前があるように、テーブルにも名前がある。また、シートに作れるのは一覧表だけ。一番上の行にカラムの名前を決める。商品というシートならそこに品番、品名、売値などがあって、それと同じという話をした。3分で理解できました。

JOIN is 何

JOINは別テーブルにある同じカラムで参照することで表を連結することでーすと説明しました。売上明細には品番はないけど、商品IDというカラムがあります。売上明細の商品IDカラムは商品テーブルのIDと同じものですので、商品IDでくっつけると横になが〜い表ができるでしょという話をしました。3分で理解できました。

こまけぇこたぁいいんだ。SQLは集合指向であることさえ伝われば。

改めて思ったのは、SQLはSELECTが9割ってことでした。おしまい。

プログラミング未経験者がSQLの習得に挑戦するでござる

etc Sql

実妹と甥っ子が、SQLの習得に挑戦するでござる。

select
  itemcode,
  name,
  lot,
  price
from
  items
where
  itemcode like '%MA-080%'
order by
  itemcode asc

元々はこんなSQLを書いているのを実妹が見ていて「これなら私でも出来そうだから教えて」と話が来た所に端を発する。

確かに言われてみれば、下記のPHPのコード(WPのfuncitions.php)よりも圧倒的に文脈がわかりやすいわ。

<?php
function custom_login_logo_url_title() {
	return 'Custom,Inc.';
}
add_filter( 'login_headertitle', 'custom_login_logo_url_title' );

 function custom_login_logo_url() {
    return get_bloginfo( 'url' );
}
add_filter( 'login_headerurl', 'custom_login_logo_url' );

データベースとのテーブルの関係なんて、Excelに例えたらブックとシートみたいなもんだ。「=Sheet2!B1」でテーブル名Sheet2の左から2番めのカラムをさしまーすとか、適当に説明が付くし。

1週間あればクロス集計ぐらいできるようになるんちゃうかな〜 先生がええからな〜(え

WordPressのwp_cronの実行スケジュール雑過ぎワロタ

WordPress

WordPressにwp_cronとかいう関数があるんで、おおデーモンになってくれて空気読んでくれるのかなとおもいきや、そんな訳がなかった。

処理がスケジューリングされていても、サイトにアクセスがなければ実行はされませんし、アクセスのあった時間が基準となるため、確実に指定時間に実行されるわけではありません。

WordPressで擬似cronを使ってバッチ処理を定期実行させる方法 | コワーキングスペース7F

なんですと。Webアクセスをきっかけにcronの実行可否を判断するわけだ。9時半にセットしても9時45分にアクセスが来たら、実行時刻は9時45分になるってことだね。なるほどね〜

ただ「定期的にWebアクセスをすればスケジュール通りに実行される」のであれば、一番簡単のはcurlするcronを仕込めばそれで終わりか。そう考えると「まぁそれもありか」という気がする。