ラーメン食べ歩き、コード殴り書き

vscode導入するので、新たに始めたこと、忘れがちなことなどを記録しておきたいメモ

.NET Core 3.1 WPF : コントロールの作成(1)

viewとviewModelは疎結合であるべき、は同意だが、あまり真面目にそこに取り組むつもりはない。 UI要素そのものがオプションやユーザー操作で動的に変化するアプリケーションがMVVMで記述できるのかも不明。 xamlの記述だけではsplitterすら満足な動作が困難に感じたので、コードビハインド(.xaml.csのこと、みたい)にも気にせずUIを記述することにする。


MVVMの問題など: MVVMを少し調べてみる - 負け犬プログラマーの歩み



■project

vsの新規作成から

1. 新規作成→プロジェクト
2. C#の"WPF アプリケーション"
  .NET core WPF アプリケーションを作成するためのプロジェクト
3. ソリューションに追加/作成の選択をし、プロジェクト名指定
4. フレームワーク指定 ".NET Core X.X"

ここではプロジェクト"XAMLtest"とする。ソースは以下の通りに自動作成される。

  1. App.xaml
  2. App.xaml.cs
  3. MainWindow.xaml
  4. MainWindow.xaml.cs


■MainWindow.xaml

基本的な記述はクラス定義、クラス保有のリソース定義、そしてUIの構造定義を記述する。 他にも有用な要素があるかもしれない。visual studioのデザイナで全てを構築できるのかは不明。



全体

サンプルコードは以下の通り。

<!-- クラス定義 -->
<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などを定義しようとすると次のようなエラーが。

f:id:heavencondition:20210511225931p:plain

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

クラスの継承、プロパティの優先順位、その他の不明瞭なルールなど果てしなく存在している。

System.Windows.FrameworkElement.DataContext

表示内容とDataContextとの関係?

Button→Content、TextBox→Textなど表示内容とプロパティの関係

コントロールに対して内容、表示設定の仕組みを調べる

Resourcesで定義できる内容


vscodeの導入

キーボードも同様だが、エディタもカスタマイズが過ぎると、いずれ開発が停止して時代に取り残された際、他の新テクノロジーに移行することが困難になる。 可能な限りニッチなカスタマイズをせず、メジャー、オフィシャルな拡張、および設定ファイルのシンプルな記述に留めて使用したい。


■キーバインディング

vscodeに移行する意味があるのかわからないがemacsバインディングをする。 本来であればこのタイミングでvisual studioベースの操作を訓練したいところではある。


拡張機能の指定

emacsバインドはいくつかあるが、Awesome Emacs Keymap が更新も続いており、ユーザー数も多そうなのでこれで決定。

1. 拡張機能からAwesome Emacs Keymapを選択
2. インストール実行
marketplace.visualstudio.com

setting.jsonの編集

デフォルトではctrl-Aの動作が異なっている様子。emacsでは行頭に移動だが、行頭↔先頭ワードのトグルになっているように見える。

    // Ctrl-Aの動作
    "emacs-mcx.strictEmacsMove": true,
setting.json

編集後、再起動しないと反映されない?

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++のフォーマッタはこちらを使用。

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タイトル

説明文


accent0 + h4

説明

1. 拡張機能からAwesome Emacs Keymapを選択
2. インストール実行

accent0 + h4

コード表記

    // markdownは先頭から記述が必要
    "test": true,
ファイル名

コメント


■言語対応のExtension

vscodeを使う主たる目的はこれだろう。 もちろんMicrosoft謹製のextensionを吊るしで使う方向で使用する。

C/C++ extension

IntelliSenseが使える。以前はなかった(?)ファイル内からの補間が可能になり、emacsにおけるdynamic abbrev相当が使えるようになったようで、vscodeへの移行を本格的に検討することにした。

C# extension

こちらもIntelliSenseが便利。MSのドキュメントでは、継承したコントロールを調べても親のプロパティが見れないが、IntelliSenseなら補間対象にしっかりと出てきてくれる。

CodeLensは行間にreferencesが表示されるのが邪魔でoffにするが、そもそもこれが何なのか全然調べていない。

Clang-Format extension

C++のフォーマッタはこちらを使用。

setting.jsonの編集

clang-formatの設定をしておく。.clang-formatファイルによるカスタムフォーマットなので"file"指定が必要。

// markdownは先頭から記述が必要
setting.json




■テスト

 バインディングをする。


拡張機能

test
拡張機能からAwesome Emacs Keymapをインストール

setting.json に以下を追加
    // Ctrl-Aの動作
    "emacs-mcx.strictEmacsMove": true,
test



aaaa
    // Ctrl-Aの動作
    "emacs-mcx.strictEmacsMove": true,
abcd

  • 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;
}