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

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で定義できる内容