.NET Core 3.1 WPF : コントロールの作成(1)
viewとviewModelは疎結合であるべき、は同意だが、あまり真面目にそこに取り組むつもりはない。 UI要素そのものがオプションやユーザー操作で動的に変化するアプリケーションがMVVMで記述できるのかも不明。 xamlの記述だけではsplitterすら満足な動作が困難に感じたので、コードビハインド(.xaml.csのこと、みたい)にも気にせずUIを記述することにする。
MVVMの問題など: MVVMを少し調べてみる - 負け犬プログラマーの歩み
■project
vsの新規作成から
ここではプロジェクト"XAMLtest"とする。ソースは以下の通りに自動作成される。
■MainWindow.xaml
基本的な記述はクラス定義、クラス保有のリソース定義、そしてUIの構造定義を記述する。 他にも有用な要素があるかもしれない。visual studioのデザイナで全てを構築できるのかは不明。
WPF4.5入門 その7 「XAMLのオブジェクト要素と名前空間」 - かずきのBlog@hatena
●WPF xamlの詳細
第4回 WPFの「リソース、スタイル、テンプレート」を習得しよう:連載:WPF入門(1/3 ページ) - @IT
●全体
サンプルコードは以下の通り。
<!-- クラス定義 --> <Window x:Class="XAMLtest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:XAMLtest" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <!-- リソース設定 --> <Window.Resources> <SolidColorBrush x:Key="brush0" Color="LightGray"/> <SolidColorBrush x:Key="brush1" Color="Gray"/> </Window.Resources> <!-- Window --> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="36" /> <RowDefinition Height="24" /> <RowDefinition Height="36" /> </Grid.RowDefinitions> <Label Grid.Row="0" Name="abc" Content="xxx" Background="#c08040"/> <Button Grid.Row="1" Content="btn0" Background="{StaticResource brush0}"/> <Button Grid.Row="2" Content="btn1" Background="{StaticResource brush1}"/> <TextBox Grid.Row="3" Text="aaa"/> </Grid> </Window>MainWindow.xaml
●クラス定義部分
コード前半はクラス定義、中はnamespaceのエイリアス定義などが自動で記述されている。
<!-- クラス定義 --> <Window x:Class="fileListView.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:fileListView" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" ResizeMode="CanResizeWithGrip">MainWindow.xaml
C#で書けば以下のような感じだろうか。
// defaultのnamespace using namespace http://schemas.microsoft.com/winfx/2006/xaml/presentation; // その他のnamespaceのエイリアス using x = http://schemas.microsoft.com/winfx/2006/xaml; using d = http://schemas.microsoft.com/expression/blend/2008; ... using local = fileListView; // projectのnamespace // class define namespace fileListView { // <Window x:Class="fileListView.MainWindow>に相当 public class MainWindow : System.Windows.Window { ... MainWindow() { Height = 450; // System.Windows.FrameworkElement.Height Width = 800; // System.Windows.FrameworkElement.Width ... InitializeComponent(); } }; }
●リソース定義部分
コード中盤はリソース定義、後半のウインドウのコントロール定義部分から参照できる。 リソース自体もstaticに記述したり、外部ファイルから取り込む、マージする、などができるようだが、詳細は先のリンクに。
ResourcesプロパティはSystems.Windows.FrameworkElement.Resourcesなので、Windowに限らず様々なcotnrolが独自に持つことができる。 親子に同名のキーで定義される場合、親方向に近い世代のリソースが適用される。
<!-- クラス定義 --> <!-- リソース設定 --> <Window.Resources> <SolidColorBrush x:Key="brush0" Color="LightGray"/> <SolidColorBrush x:Key="brush1" Color="Gray"/> </Window.Resources>MainWindow.xaml
ResourceDictionary Resources なので、Item[]を持っているのでobjectを保持しているはずだが、例えばstringなどを定義しようとすると次のようなエラーが。
WPFで定められているクラスを、IDictionnaryで検索する"x:Key"で定義する必要があるようだが、どのクラスが管理されているのかは不明。
●コントロール定義部分
コード後半はコントロール定義、ここではWindowの中身の配置を定義する。
<!-- Window --> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="36" /> <RowDefinition Height="24" /> <RowDefinition Height="36" /> </Grid.RowDefinitions> <Label Grid.Row="0" Name="abc" Content="xxx" Background="#c08040"/> <Button Grid.Row="1" Content="btn0" Background="{StaticResource brush0}"/> <Button Grid.Row="2" Content="btn1" Background="{StaticResource brush1}"/> <TextBox Grid.Row="3" Text="aaa"/> </Grid>MainWindow.xaml
StaticResourceによってリソースをバインドしている部分が重要。
Gridをテストとして使用。RowDefinitionsでstretchさせるコントロールの指定は"*"で示す。
プロパティにリソースを割り当てるのもリストの通り。
コントロールのプロパティ→リソース定義→コードビハインドにバインドし、ダイナミックに内容を変更するのが一つの目標になる。
■todo
クラスの継承、プロパティの優先順位、その他の不明瞭なルールなど果てしなく存在している。
vscodeの導入
キーボードも同様だが、エディタもカスタマイズが過ぎると、いずれ開発が停止して時代に取り残された際、他の新テクノロジーに移行することが困難になる。 可能な限りニッチなカスタマイズをせず、メジャー、オフィシャルな拡張、および設定ファイルのシンプルな記述に留めて使用したい。
■キーバインディング
vscodeに移行する意味があるのかわからないがemacsバインディングをする。 本来であればこのタイミングでvisual studioベースの操作を訓練したいところではある。
●拡張機能の指定
emacsバインドはいくつかあるが、Awesome Emacs Keymap が更新も続いており、ユーザー数も多そうなのでこれで決定。
●setting.jsonの編集
デフォルトではctrl-Aの動作が異なっている様子。emacsでは行頭に移動だが、行頭↔先頭ワードのトグルになっているように見える。
●keybindings.jsonの編集
吊るしの状態で使いたいが、以下のスクロール、undo/redoに関するキーだけは定義しておく。本当はhalf scrollとか欲しい。file openはダイアログが開いてしまい、使い勝手が悪い。
せっかくなのでemacsながらwindowsベースのcopy/pasteを取り入れ、徐々にvisual studio標準に体を近づけていくことにする。
// scroll { "key": "ctrl+up", "command": "cursorPageUp", "when": "textInputFocus" }, { "key": "pageup", "command": "-cursorPageUp", "when": "textInputFocus" }, { "key": "ctrl+down", "command": "cursorPageDown", "when": "textInputFocus" }, { "key": "pagedown", "command": "-cursorPageDown", "when": "textInputFocus" } // // redo : ctrl + shift + / { "key": "ctrl+shift+/", "command": "redo", } // redo : ctrl + shift + \ { "key": "ctrl+shift+\\", "command": "redo", } // undo : ctrl + \ { "key": "ctrl+\\", "command": "undo", } // // file open { "key": "ctrl+x ctrl+f", "command": "workbench.action.files.openFile" } // // // // // // 全選択(windows ctrl+A) { "key": "ctrl+alt+a", "command": "editor.action.selectAll" } // // コピー : windowsコマンドを割り当ててしまう { "key": "ctrl+c", "command": "emacs-mcx.copyRegion", } // // ペースト : windowsコマンドを割り当ててしまう { "key": "ctrl+v", "command": "emacs-mcx.yank", "when": "editorTextFocus && !editorReadonly" }keybindings.json
■言語対応のExtension
vscodeを使う主たる目的はこれだろう。 もちろんMicrosoft謹製のextensionを吊るしで使う方向で使用する。
●C/C++ extension
IntelliSenseが使える。以前はなかった(?)ファイル内からの補間が可能になり、emacsにおけるdynamic abbrev相当が使えるようになったようで、vscodeへの移行を本格的に検討することにした。
●C# extension
こちらもIntelliSenseが便利。MSのドキュメントでは、継承したコントロールを調べても親のプロパティが見れないが、IntelliSenseなら補間対象にしっかりと出てきてくれる。
CodeLensは行間にreferencesが表示されるのが邪魔でoffにするが、そもそもこれが何なのか全然調べていない。
●Clang-Format extension
C++のフォーマッタはこちらを使用。
marketplace.visualstudio.com 2. C#
marketplace.visualstudio.com 3. Clang-Format
marketplace.visualstudio.com
●setting.jsonの編集
clang-formatの設定をしておく。.clang-formatファイルによるカスタムフォーマットなので"file"指定が必要。
//-------------------------------------------------- // Clang-Format拡張 //-------------------------------------------------- // clang-formatのパス "clang-format.executable": "d:/windows/bin/clang-format.exe", // fileで指定 "C_Cpp.clang_format_style": "file", // // //-------------------------------------------------- // C# : Microsoft C#拡張 : formatter込み //-------------------------------------------------- // C# : referencesをoffにする "editor.codeLens": false,setting.json
■その他のカスタマイズ
さすがに吊るしでは不便なことが多く、あまり変なことはしない程度にカスタマイズしておく。
●細かい設定
■files.exclude
除外するファイルを指定。少なくともプロジェクトのエクスプローラに反映される。その他何に影響するかは不明。
■files.associations
特定の拡張子のファイルに対して、任意の言語サポートをバインドする。
■window.newWindowDimensions
起動時のウインドウサイズを設定。前回終了時を引き継がせたい。
■workbench.editor.tabCloseButton
ファイルtabのcloseボタンを間違ってクリックするミスを防げる。"workbench"がどの範囲を示すか不明。
■editor.renderIndentGuides
インデントのガイドラインが邪魔だったので消す。
■editor.formatOnSave
セーブ時にformatterを実行する。
■editor.renderWhitespace
空白文字を表示するか。
■editor.renderControlCharacters
制御文字を表示するか。
■editor.minimap.enabled
イマドキっぽくて見栄えするが、結局役にたたなかったミニマップの制御。
■editor.lineNumbers
行番号表示
■editor.wordBasedSuggestions
ファイル内の単語を補完対象とする。
//-------------------------------------------------- // default //-------------------------------------------------- // 無視するファイル "files.exclude": { "**/*.*~": true }, // // 拡張子追加 "files.associations": { "*.hlsl": "cpp", "*.cg": "cpp" }, // // // 起動時のウインドウサイズ "window.newWindowDimensions": "inherit", // // // tabのcloseボタンをoffにする "workbench.editor.tabCloseButton": "off", // // // インデントガイド(インデントに沿って縦線を表示) : 色指定を参照 "editor.renderIndentGuides": false, // // セーブ時にformatter実行 "editor.formatOnSave": true, // // 入力時にformatter実行 "editor.formatOnType": true, // // etc "editor.renderWhitespace": "none", "editor.renderControlCharacters": false, "editor.minimap.enabled": false, "editor.lineNumbers": "on", // // ファイル内の単語を補完対象とする "editor.wordBasedSuggestions": true,setting.json
●フォント設定
デフォルトの"Consolas"ファミリーは綺麗でいかにもイマドキなエディタだが12pixelでは無駄に詰まって見づらい。やはり装飾性皆無、system font的なMSゴシックにせざるを得ないのか。
■edigot.fontSize
フォントサイズ
■edigot.lineHeight
改行サイズ
■editor.fontFamily
フォント
//-------------------------------------------------- // font //-------------------------------------------------- "editor.lineHeight": 12, "editor.fontSize": 12, "editor.fontFamily": "MS ゴシック, 'Courier New', monospace",setting.json
●カラー設定
//-------------------------------------------------- // color theme //-------------------------------------------------- "workbench.colorTheme": "Visual Studio Dark", "editor.colorCustomizations": { "comments": "#FF0000" }, "editor.tokenColorCustomizations": { "comments": "#f01010" }, "workbench.colorCustomizations": { // 背景色 "editor.background": "#101040", // インデントガイドの色を明るい青色( "#aaf" ) "editorIndentGuide.background": "#181840", // // scroll bar "scrollbarSlider.background": "#404080", "scrollbarSlider.hoverBackground": "#5050a0", "scrollbarSlider.activeBackground": "#6060c0", // tab color "tab.activeBackground": "#4060a0", },setting.json
■todo
せっかくのvscodeなのでIDE的にビルド、デバッグ、ソース管理なども取り入れたいが、追求するとキリがないので現段階ではここまでにしておく。以下、今後調べたいこと。
●プロジェクト管理、ビルド、デバッグ
visual studio同等のことができるのか?
●git(github)
tortisegitに慣れているので、移行する気はないが、一応調べておきたい。
●言語対応
追加されている機能について。カスタマイズなど。
■その他
軽量、高速、とのことだが、メモリ使用量はxyzzyのざっと100倍。xyzzyが100KBで収まっていたところ、vscodeでは10MBのメモリ圧迫。ファイルを多数開いたらどうなることか。
markdownによるコードセクション表示が楽そうだからはてなブログにしたのだが、ここで問題が起きてしまった。 vscodeで編集、そのまま記事にコピペ、のつもりだったのが、整形されるとマークダウン書式がインデントされてしまい、マークダウンとして認識されなくなってしまう。 そのうちformatterに手を入れたいが、とりあえずどうにかしておくしかない。
ページテスト
■h1タイトル
説明文
■言語対応のExtension
vscodeを使う主たる目的はこれだろう。 もちろんMicrosoft謹製のextensionを吊るしで使う方向で使用する。
●C/C++ extension
IntelliSenseが使える。以前はなかった(?)ファイル内からの補間が可能になり、emacsにおけるdynamic abbrev相当が使えるようになったようで、vscodeへの移行を本格的に検討することにした。
●C# extension
こちらもIntelliSenseが便利。MSのドキュメントでは、継承したコントロールを調べても親のプロパティが見れないが、IntelliSenseなら補間対象にしっかりと出てきてくれる。
CodeLensは行間にreferencesが表示されるのが邪魔でoffにするが、そもそもこれが何なのか全然調べていない。
●Clang-Format extension
C++のフォーマッタはこちらを使用。
marketplace.visualstudio.com 2. C#
marketplace.visualstudio.com 3. Clang-Format
marketplace.visualstudio.com
●setting.jsonの編集
clang-formatの設定をしておく。.clang-formatファイルによるカスタムフォーマットなので"file"指定が必要。
■テスト
バインディングをする。
●拡張機能
// Ctrl-Aの動作 "emacs-mcx.strictEmacsMove": true,test
// Ctrl-Aの動作 "emacs-mcx.strictEmacsMove": true,
- setting.json の設定
// Ctrl-Aの動作 "emacs-mcx.strictEmacsMove": true,
class Foo def bar'baz' # return baz end end
public static ObservableCollection<ListViewContents> buildDirectoryFileList(DirectoryFileCollection dirFiles, string regexString, ListViewSorter sorter) { // dir, fileそれぞれでsort適用 var dirList = collectDirectoryList(dirFiles, sorter); var fileList = collectFileList(dirFiles, sorter); dirList.AddRange(fileList); // ListViewContents ObservableCollection<ListViewContents> dst = new ObservableCollection<ListViewContents>(dirList); return dst; }
//-------------------------------------------- // test //-------------------------------------------- float ClassName::initialize( const int val) { // comment float valf = (int)val * 2.0f; return valf; }