コントラスト比のISO・WCAG基準は不適切(特に白抜きの文字の場合)
文字と背景色のコントラスト比について、ISO/WCAGで推奨値が定められている。解説ページは色々あるが、とりあえずWCAG2.0の日本語訳解説はこちら。ISO-9241-3及びANSI-HFES-100-1988に基づいているとされている。
達成基準 1.4.3 を理解する | WCAG 2.0解説書
達成基準 1.4.6 を理解する | WCAG 2.0解説書
これを鵜呑みにしている解説記事の多いこと…。で、文字が白抜きの場合にこの推奨値を適用するとおかしいだろという話。
白抜き文字の場合でも黒文字と同じコントラスト比の基準を適用するのはおかしいと思う。1枚目と3枚目は同等か、1枚目の方が見やすいと思う。 pic.twitter.com/ieczwXoB4I
— cactuaroid (@cactuaroid) 2020年8月13日
確かに黒字だと4.5:1を下回ると相当厳しいし、7:1を超えていて欲しいのは分かる。 pic.twitter.com/IojjiYzZBi
— cactuaroid (@cactuaroid) 2020年8月13日
"contrast white text"とかでググってみるといくつか記事が見つかった。
For many of us, some of these combinations are not very readable. That is why 4.5:1 is a minimal contrast ratio.
多くの人にとって、これらの組み合わせの中には、あまり読みやすくないものもあります。だからこそ、4.5:1は最低限のコントラスト比なのです。
WebAIM: Contrast and Color Accessibility - Understanding WCAG 2 Contrast and Color Requirements
Myth 1: The WCAG requirements are always optimal
One case where the WCAG standards aren’t applicable is with the brightness contrast of white text.
迷信1:WCAG要件は常に最適である
WCAG規格が適用されないケースの一つに、白文字の明るさのコントラストがあります。
The Myths of Color Contrast Accessibility
もう少し探してみると、この「The Myths of Color Contrast Accessibility」の記事に対する返答の記事を見つけた。
There is no "Myths of Color Contrast Accessibility"
この中で、WCAG2.2および3.0に向けて以下の議論が行われていることが分かった。
Contrast Ratio Math and Related Visual Issues · Issue #695 · w3c/wcag · GitHub
The W3C's specification for determining sRGB contrast as discussed in "Understanding WCAG 2.0 and 2.1, Minimum Contrast 1.4.3" is not perceptually uniform and as a result creates "contrast ratios" that are not meaningful.
「Understanding WCAG 2.0 and 2.1, Minimum Contrast 1.4.3」で説明されているsRGBコントラストを決定するためのW3Cの仕様は、知覚的に均一ではなく、その結果、意味のない「コントラスト比」が作成されます。
...
we've found that the issue is not so much using "simple contrast" as it is the manner (or lack of) considering ambient lighting, the nature of illuminated displays, and/or a lack of math that better models human non-linear perception.
問題は「単純なコントラスト」を使用しているからというよりも、環境照明、ディスプレイの性質、および/または人間の非線形知覚をよりよくモデル化する数学が欠如しているからということがわかりました。
...
With a random set of colors, about 50% false passes and 22% false fails compared to a perceptually uniform prediction model such as SAPC.
ランダムな色の組を評価すると、SAPCのような知覚的に均一な予測モデルと比較して、約50%の偽合格と約22%の偽失敗が発生します。
...
The new methods are part of 3.0, as they are a complete break from the current methods. As such, discussing the current methods is somewhat moot — those are not going to change.
新しい手法は3.0の一部であり、現在の手法から完全に脱却したものです。このように、現在の手法を議論することはやや無意味です - それらは変更されないでしょう。
やはり、現状のコントラスト比の計算方法・推奨値は問題が多く当てにならないようだ。根本的に計算方法を変更する必要があるため3.0での更新を目指している模様。
開発中のツールも紹介されていて参考にはなるが、議論を斜め読みするだけでも相当複雑な問題領域であることが分かるので、現時点では実際のUIで実際のハードウェアで実際の使用環境において色々な人に見てもらって評価した結果を重視しよう、というのが私の結論。同じ配色でも、フォント・サイズ・ウェイトや文字の使われ方(本文かヘッダかボタンキャプションか)、ディスプレイの明るさや解像度によって妥当かどうかはものすごく変わる。
とりあえず、文字が白抜きの場合は太字にすること。
SQL Serverの変更検出のメモ
SQL Serverで特定のテーブルに変更が発生したことを検出して色々したい。できれば、どの行が追加/編集/削除されたかが欲しい。
まずクエリ通知というのが見つかる。クエリの結果に変更がある場合に通知してくれるが、どの行に変更があったのかは分からない代物。ともかく試してみる。
SQL Server のクエリ通知 - ADO.NET | Microsoft Docs
手順はここに説明があるが、
SqlDependency を使用した変更の検出 - ADO.NET | Microsoft Docs
詳細な手順はここが参考になる。
Using SqlDependency To Monitor SQL Database Changes - C# Tutorials | Dream.In.Code
OnChangeイベントは一度しか発生しないらしい。
c# - SQLDependency_OnChange-Event fires only one single Time - Stack Overflow
Delete/Insert/Updateのどれかが発生したことは分かるが、やはりそれだけだった。クエリ結果を画面に表示している場合などで、常にクエリ結果を最新に保つ目的に特化していると分かった。
どの行に変更があったのかを知る方法は標準ではなさそう。このライブラリを使うのが良いらしい。まだ試していない。
How to monitor SQL Server table changes by using c#? - Stack Overflow
BinaryFormatterによるDeep Copyと明示的実装の違い
お手軽にDeep Copyを実現するなら、BinaryFormatterが使われることがあるが、かなり処理時間がかかるため、速度を重視するなら明示的にDeep Copyを実装する必要がある。ぶら下がっている型全てで明示的に実装する必要はあるが、大抵は特に問題なく実装できるだろう。しかし、BinaryFormatterによるDeep Copyと、典型的な明示的実装には一部大きな違いがある。
下図の構造のインスタンスがあったとする。BinaryFormatterによるDeep Copyでは、オブジェクトグラフを完全に複製する。一方で、典型的な明示的実装ではツリー構造に変化してしまう。これは明示的実装でなくとも、XML・JSONなどへ単にシリアライズ・デシリアライズすることでDeep Copyした場合も同じだ。
元の構造を維持したい場合、それなりに工夫する必要がある。
例えば、そのオブジェクトグラフにおいて各インスタンスのIdが必ずユニークであるという前提があるならそれを利用して、一度コピーしたIdのインスタンスは再度コピーしないようにキャッシュすればよい。連鎖的なコピーの最初にキャッシュを作って持ちまわる。
GitHubでコントリビュートする流れメモ
たまにしかやらなくてTFSと勝手が違ってていつも調べるのでメモ。
- オリジナルのリポジトリからFork(自分のリポジトリを作成)して、自分のリポジトリからClone(ローカルへ取り込み)する。
- 自分のリポジトリでPull Request用にブランチを切って作業する。TFSと違い、コミットではなくブランチをマージすることになる。
- 無印のmasterブランチとかがローカルのリポジトリで、remoteとついているのがGitHub側。remote/originがGitHubの自分のリポジトリ。
- オリジナルのリポジトリは
git remote add upstream git://github.com/octocat/Spoon-Knife.git
で登録しておく。remote/upstreamになる。この操作はVisual Studio上では出来なさそう。
- オリジナルのリポジトリは
- upstreamの最新を取り込むときは、Fetchしてマージしてoriginへpushする流れ。
- コマンドラインでやる場合は
git fetch upstream
、git merge upstream/master
- コマンドラインでやる場合は
- あとはPull Requestを出すだけだが、出した後もそのブランチへのコミットはPull Requestに反映されていくことに注意。(Pull Requestは出した時点までのコミットの取り込みではなく、ブランチの取り込みを要求する)
参考:
LINQで非同期ラムダを待機する
System.Linq.Asyncのバージョン4.0.0で、LINQの各メソッドに非同期ラムダを受けて待機するバリエーションである~Awaitシリーズが追加された。以前までは自分で用意する必要があって微妙でIssueもいくつか立っていたが、パッケージに含まれるようになったので楽!
例)
var array = new[] { 1, 2, 3 }; var tasks = array.Select((x) => GetAsync(x)); // Task.WhenAll(tasks) ...
みたいな書き方をすると、非同期ラムダ式の戻り型はTaskなので、複数のTaskが生成されてGetAsyncが全て並列に動く(正確にはawaitのタイミングでTaskが返って次が走り始める)。これを、1つずつ直列にただし非同期で動かしたいとする。
var array = new[] { 1, 2, 3 }; var tasks = array.Select((x) => GetAsync(x)); foreach (var task in tasks) { var value = await task; // ... }
これだけならTaskを1つずつawaitすれば事足りる。しかしSelectの後段でLINQメソッドをつなげたい場合はIAsyncEnumerable
var array = new[] { 1, 2, 3 }; var values = array .ToAsyncEnumerable() .SelectAwait(async (x) => await GetAsync(x)) .ToArray();
以前の自前実装したものとSelectAwaitを使ったものと、両方こちらの回答に書いた。
SelectAwaitに限らず、ForEachAwaitAsyncなどIAsyncEnumerable
C#アプリのAPIをOPC UAサーバとして公開したいので下調べ
2022/12/19追記
試した結果をまとめました。 qiita.com
OPC UAサーバを開発するために情報を集めた。C#アプリケーションのRPC的なAPIを公開することが念頭にあるので、C言語向けだったりPLC向けだったり情報を垂れ流すのみ系は無視している。
OPC UAサーバを開発する方法
OPC UA対応を行うには、一般的には専用のハードウェアを使用するか、OPC Foundationが提供するOPC UA StackもしくはSDK(Software Development Kit)を活用してOPC UAを装置に組み込むという2つの方法がある。
OPC UAの技術進化、Pub-Sub通信やセキュリティ技術など実用面強化:いまさら聞けないOPC UA入門(3)(1/2 ページ) - MONOist
OPC UA Stackをまず見てみる。
GitHub - OPCFoundation/UA-.NETStandard: OPC Unified Architecture .NET Standard
サンプルを動かしてみたがなんかややこしい印象。XMLからクラスとか生成するにはUA Model Compilerを使うっぽい。GUIツールなどはなくXMLはベタ書きするらしい。
GitHub - OPCFoundation/UA-ModelCompiler: ModelCompiler converts XML files into C# and ANSI C
情報モデルを自作する方法についてはこちらが参考になりそう。
How to create custom OPC UA Information Models • OPC UA rocks
SDKの必要性
OPC UA SDKs and Toolkits | OPCconnect.com
While a stack and examples provides the basic communications infrastructure, a full SDK adds significant application layer libraries and classes to speed up application development. UA developers are recommended to look to one of the third-party vendors listed on this page.
公式実装は、OPC UA Stackとしてインフラストラクチャを提供するが、アプリケーション層の機能を提供する3rdパーティ製のSDKを使うことが推奨されている。なるほど、公式サンプルでの印象は間違っていなかった。
C#でOPC UAサーバを開発できるSDKを探してみると、Unified Automationのがドキュメント・サポートも含めて評判が良い。
OPC-UA client SDK for C#.NET application development - Stack Overflow
Choose SDK - Unified Automation
確かにOPC UA Stackの上にSDKレイヤが載っている。
SDK以外だと、汎用のOPC UAサーバプロセスの上で追加実装することで、既存インターフェースをOPC UAに変換するソリューションも見つかった。
東芝インフラシステムズのは.NET Framework 4.5と書いてあるので使えるかも。
https://www.toshiba.co.jp/sis/seigyo/cnt/prod/ciemac/opcua/index_j.htm
EmpressのはC/C++っぽいので使えない/使いにくそう。
どう開発するか
私の場合はAPIがまだないアプリケーションにOPC UAのAPIを設けようとしている。選択肢は三つ。
- アプリケーションに別途APIを用意してから、別ハードor別プロセスで動作する3rdパーティOPC UAサーバ製品から繋いで公開する
- アプリケーションに別途APIを用意してから、別プロセスで動作するOPC UAサーバも自分で用意してそこから繋いで公開する
- ローカルでの通信部分はセキュリティを気にしなくて良い
- 原価は抑えられるが自分で考えることも増える
- アプリケーションに直接OPC UAサーバを実装する
バランスが取れるのは2番目か。まず3番目で進めて評価とかして、後でOPC UAサーバ部分を分離する必要が出てから分離しても遅くはないか。
OPC UAの一般的な概要を理解するための記事
インダストリー4.0の推奨規格「OPC UA」、パブサブモデルでスマート工場に対応:産業用ネットワーク(1/2 ページ) - MONOist
インダストリー4.0で重要な役目を果たす、Windows生まれの「OPC UA」:IoT観測所(20)(1/3 ページ) - MONOist
OPC UAはなぜ「安全に」通信が行えるのか:OPC UA最新技術解説(3)(1/3 ページ) - MONOist
OPC UAとは何か?なぜ「製造業とITの橋渡し役」として最適なのか インダストリー4.0採用やOSS化で大注目|ビジネス+IT
オリジナル解説 OPC UAとは?- 第1回 OPC UAの概要 | オムロン制御機器
産業IoT界隈では良く使われるらしい国際規格OPC-UAについて調べた - Qiita
OPC UA Companion Specifications (OPC UA CS) | OPCconnect.com
書籍
概要をつかむ系
https://www.amazon.co.jp/OPC-Unified-Architecture-Information-Technology/dp/1530505119
仕様をきっちり理解する系
https://www.amazon.co.jp/OPC-Unified-Architecture-Wolfgang-Mahnke/dp/3642088422/
COMポートの詳細設定画面をC#から開く
COMポート番号を変更したい場合、通常は以下のようにデバイスマネージャから詳細設定画面を開く必要がある。C#のアプリケーションでRS232C接続をする場合、RS232C-USB変換アダプタを使うのが一般的だと思うが、この時COMポート番号が不定になってしまい、環境ごとにデバイスマネージャからこの画面を開くのが手間で改善策を検討した。
しかし、コマンドラインからCOMポート番号を変更するには恐らくレジストリを直接いじるような方法しか見当たらず、怖いので完全自動化は諦めて、以下を参考にして、必要なタイミングでこの詳細設定画面を直接プログラムから開いて手動設定する代替案を実装した。
ついでに、SerialDisplayAdvancedSettingsがPInvoke.netに載っていなかったので追加した。
https://www.pinvoke.net/default.aspx/msports/SerialDisplayAdvancedSettings.html