Windowsフォームデザイナーでツールボックスからカスタムコントロールを追加する場合の注意点
Visual Studio Community 2013で、C#で、Windows Formsでアプリ書いているんだが、なかなかやっかいなはまり方することが多くて困る。
今日はListViewを、継承してカスタムしたクラスに置き換えようとしてはまった。
カスタムコントロールを作るまでは、MSDNに書いてある感じでまあ問題ない。
方法 : 既存の Windows フォーム コントロールから継承する
問題はこのカスタムコントロールを、フォームデザイナーを使って、ツールボックスから追加しようとした場合に起きる。
上記の手順で追加した場合、カスタムコントロールはWindowsフォーム本体と同じ名前空間に属する。それ自体は自然だし問題ない。
だがフォームデザイナーがどうも、コントロールとフォーム本体が同じ名前空間に属する場合を想定していないようで、おかしなコードを出力する。
namespace MyApp { partial class MyApp { ... private void InitializeComponent() { this.listView1 = new MyApp.ListView(); ... } ... } }
このコードが生成される、 myapp.designer.cs
ファイルの名前空間は MyApp
になっているので、コンパイラが MyApp.MyApp.ListView
を見ようとしてエラーになる。
型名 'ListView' は型 'MyApp.MyApp' に存在しません。
対策としては、手動で書き換えるしかなさそうだ……。
今は大丈夫だけど、これからコントロールが増えてきたらどうしよう。
- フォームデザイナーなんて使わず、手動で書く。
- WPFに移行する。
どっちがいいだろうかね。困った。
おまけ
カスタムコントロールの方のクラスはまあこんな感じになるわけだが、
namespace MyApp { public partial class ListView : System.Windows.Forms.ListView { public ListView() { InitializeComponent(); } } }
間違ってこう書くと、名前が被ってエラーになる。
using System.Windows.Forms; namespace MyApp { public partial class ListView : ListView { public ListView() { InitializeComponent(); } } }
'MyApp.ListView' と 'MyApp.ListView' を含む、循環する基本クラスの依存関係です。
まあ、ちゃんと文法わかってればない間違えなんだけど。
追記。
どうも、フォームデザイナーで修正する度に書き換えられちゃう模様。本気でどうにかしないと……。
C#のcatchがちょっと面白い
最近C#をちょっと書いているのだが、まったく未知のところからやっているとつい変なコードを書いてしまう。
先日は、こんなコードを書いた。
using System; // for Exception class Program { private static void Main() { try { throw new Exception("error!"); } catch (Exception) { } } }
見ての通り、catch
句に受け取る型名しか書いていない。なんでこんなことが起きるのかとTwitterでつぶやいたら、こんな感じで教えていただいた。
@xxmagai エラー情報を参照しない場合は、変数の記述は不要ですね。エラー情報を参照せず、後片付けしか行わない時に使います。catchブロックの中でthrow;って書くともう一度例外が投げれるので、片付けして再送出するみたいな場合も書かないです。
— neko (@techno_neko) 2015, 6月 27
実用的には、あるクラスの例外だけ再スローして、ほかの例外は処理する、などに使えるのだろう。
using System; class ExceptionA : Exception { // 関係ないけどコンストラクタいちいち書かないといけないのなんとかならんの? public ExceptionA(string message) : base(message) { } } class Program { private static void Main() { try { throw new ExceptionA("error!"); } catch (ExceptionA) { // こうすると再スローできる throw; } catch (Exception e) { // ExceptionA以外のExceptionクラスの例外は、処理する Console.Write(e); } // こうすると残りぜんぶ取れる catch { } } }
型のゆるい言語を使っていると、catchした後にクラスを見て処理とか考えてしまうが、型の厳しい言語ではこういうやり方があるのだろう。
型の厳しい言語はほとんど使ったことがないので勉強になる。
QuickRunでC#叩けるようにする……までもなかった話
QuickRunはC#デフォルトで対応していた
なにを間違ったかC#書いてて、基本はIDEでいいのだけど、ちょっとしたことを試すのにQuickRunが使いたくなったのであちこち検索して設定してみた。
のだが、さらに調べるとそもそもQuickRunは現在デフォルトでC#に対応していた。
最初動かなくて気付かなかったがそれはPATHを設定していなかっただけだった。のでPATHを設定。
PATHには、C:\Windows\Microsoft.NET\Framework64\v4.0.30319
とか、csc.exe
がある場所を指定すればいい。
だが出力が文字化けた。調べてみると、termencoding
が空だった。set encoding=utf8
していなければそれでも大丈夫だった気がするが、してたのでまあ、termencoding
も設定。
set termencoding=cp932
手動設定を試していたときに :@"
ではまった件
この間のKindleのセールで買ったVimテクニックバイブルをちびちび進めていて、その中にあった、Vimスクリプトをコピーして :@"
で実行、というテクニックを最近使っていたのだが、
let g:quickrun_config = { \ ...
みたいなスクリプトでエラー (E15
) が出る。
:h :@
で調べてみたところ、 :@{register}
での実行は、Exコマンドを連続実行してるだけみたいな感じで、どうも行の継続は無理っぽい。
対処法が思い付かなかったが、QuickRunはVimスクリプトも当然対応しているので変なことせずにQuickRun使えば大丈夫だった。
QuickRunマジ便利という話。
Angular.jsとBootstrapを競合させずに使う
普通にやったらアウトっぽい。
知らずにBootstrapに後からAngular.js突っ込んでてうまく動かなかったので、以下の手順でなんとかした。
- jquery.js, bootstrap.jsを外す。
bower install angular-ui-bootstrap-bower --save
- angular-ui-bootstrapってのもあるが、こっちは依存がやたら多く、ソースからコンパイル用っぽい。
angular.module()
の第2引数でui.bootstrap
への依存を指定。- Bootstrapのオリジナルの動作指定は使えないので、ここの下の方を参考に、HTMLを書き換える。
つーか最初からちゃんとやってればよかった。
Vimで、式用コマンドラインモードの履歴をコピーする方法
Vimでは、ノーマルモードでのp
, P
によるレジスタ貼り付け以外に、挿入モードでのCTRL-R
からの貼り付けがある。
貼り付けられるレジスタにはいくつか特殊なものがあるが、特に=
の挙動は変わっていて、これを入力すると、式用のコマンドラインモードになる。
このモードで入力した文字列は式として評価され、その戻り値が貼り付けられる。
簡単だが式が長くなるような計算などで便利でよく使うのだが、今回、入力した式の方を後から再利用したくなった。
コマンドラインモードの履歴を扱うには、コマンドラインウィンドウを開けばいい。
通常のコマンドラインモード用なら、q:
でおっけー。:q
を打ち間違えることで出てきたりするので、多分みんな知ってる。
検索用ならq/
, q?
.
だが、式用のキーバインドが見つからない。q=
にはなにも割り当てられていないようだし。
ということで:h q:
から調べてみたところ、
1. コマンドラインモードで、オプション 'cedit' で指定されたキーを使う。 'compatible' がオフのときの既定値は CTRL-F である。
これで開けるということだった。今回の場合、i_CTRL-R_=
で式用コマンドラインモードを開いた上で、CTRL-F
を入力することで行けた。
便利。とはいえq=
も欲しかった。
HTML(など)で使うURIの相対的な表記方法についてまとめる
いい加減「ネットワークパス参照」とか覚えたいので。
とはいっても、基本的にはRFC 3986を読めば書いてあるのだが。
Uniform Resource Identifier (URI): 一般的構文
//
で始まるやつ。- 「ネットワークパス参照」
- 昔はあまり見なかったが、httpsや、外部でホスティングされているJavaScriptの使用が流行ったせいで最近ではけっこう見る。
- この名前だと誰も覚えられないと思う。「スキーム相対」とかそんな感じにしてはどうか。関係ないがスキームとスキーマがどっちがどっちかも覚えられない。
/
で始まるやつ。- それ以外。
それにしても問題は、人に伝えるときだ。どの表記方法も、正しい名前ではまず通用しないと思われる。
かといって十分に知れ渡った慣用名があるという感じでもない。実例を出しつつ伝えるのがベターか。