Skip to content

Commit

Permalink
Updated readme.
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed May 28, 2024
1 parent b7c7e12 commit e31c50c
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 150 deletions.
Binary file removed Images/vswizard_en.png
Binary file not shown.
Binary file removed Images/vswizard_ja.png
Binary file not shown.
192 changes: 118 additions & 74 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
|Epoxy.Avalonia11|[![NuGet Epoxy.Avalonia11](https://img.shields.io/nuget/v/Epoxy.Avalonia11.svg?style=flat)](https://www.nuget.org/packages/Epoxy.Avalonia11)|Avalonia version 11|
|Epoxy.Avalonia|[![NuGet Epoxy.Avalonia](https://img.shields.io/nuget/v/Epoxy.Avalonia.svg?style=flat)](https://www.nuget.org/packages/Epoxy.Avalonia)|Avalonia version|
|Epoxy.OpenSilver|[![NuGet Epoxy.OpenSilver](https://img.shields.io/nuget/v/Epoxy.OpenSilver.svg?style=flat)](https://www.nuget.org/packages/Epoxy.OpenSilver)|OpenSilver version|
|Epoxy.Xamarin.Forms|[![NuGet Epoxy.Xamarin.Forms](https://img.shields.io/nuget/v/Epoxy.Xamarin.Forms.svg?style=flat)](https://www.nuget.org/packages/Epoxy.Xamarin.Forms)|Xamarin Forms version|
|Epoxy.Maui|[![NuGet Epoxy.Maui](https://img.shields.io/nuget/v/Epoxy.Maui.svg?style=flat)](https://www.nuget.org/packages/Epoxy.Maui)|.NET MAUI version|

## NuGetパッケージ F#専用
Expand All @@ -25,12 +24,6 @@
|FSharp.Epoxy.Avalonia11|[![NuGet FSharp.Epoxy.Avalonia11](https://img.shields.io/nuget/v/FSharp.Epoxy.Avalonia11.svg?style=flat)](https://www.nuget.org/packages/FSharp.Epoxy.Avalonia11)|Avalonia version 11|
|FSharp.Epoxy.Avalonia|[![NuGet FSharp.Epoxy.Avalonia](https://img.shields.io/nuget/v/FSharp.Epoxy.Avalonia.svg?style=flat)](https://www.nuget.org/packages/FSharp.Epoxy.Avalonia)|Avalonia version|

## dotnet CLIテンプレート

|Package|main|Description|
|:--|:--|:--|
|Epoxy.Templates|[![NuGet Epoxy.Templates](https://img.shields.io/nuget/v/Epoxy.Templates.svg?style=flat)](https://www.nuget.org/packages/Epoxy.Templates)|dotnet CLI template package|

## これは何?

* Epoxyは、.NET XAML環境で使える、Model-View-ViewModel (MVVM) アーキテクチャ向けの、独立した柔軟性のあるライブラリです。
Expand All @@ -39,7 +32,6 @@
* WPF: .NET 8.0/7.0/6.0/5.0, .NET Core 3.0/3.1, .NET Framework 4.5/4.8
* Avalonia: [Avalonia](https://avaloniaui.net/) (New v11 or 0.10 series)
* OpenSilver: [OpenSilver](https://opensilver.net/) (1.0.0 or higher)
* Xamarin Forms: [Xamarin Forms](https://github.com/xamarin/Xamarin.Forms) (5.0.0.1874 or higher)
* .NET MAUI: 7.0 or higher
* 非同期処理 (async-await) を安全に書くことが出来るように配慮しています。
* C# 8.0でサポートされた、null許容参照型を使えます。
Expand All @@ -53,85 +45,46 @@
* それぞれの機能が、相互に関係「しません」。独立しているので、自由に組み合わせることが出来ます。
* ほかのフレームワークライブラリ(例: ReactiveProperty)と組み合わせて使えるように、余計な操作や暗黙の前提を排除しています。

### 解説動画があります (YouTube, 日本語のみ):

[![Epoxyで C# MVVMアーキテクチャを簡単に実装する話 - 作ってみた 第一回](https://img.youtube.com/vi/LkyrgJbuiQs/0.jpg)](https://www.youtube.com/watch?v=LkyrgJbuiQs)

[(再生出来ない場合はこちら)](https://www.youtube.com/watch?v=LkyrgJbuiQs)


## サンプルコード

様々な環境の実働サンプルがあります。
このサンプルは、The Cat APIから、最新の投稿記事と画像を非同期でダウンロードしながら、
リスト形式で表示するものです。

サンプルコードプロジェクトは、[playgroundディレクトリ](playground/) 、又はF#のサンプルコードは [playground.FSharpディレクトリ](playground.FSharp/)
にあります。

### ビルドテンプレートとビルド方法

注意: 将来のバージョンで、テンプレートプロジェクトは廃止されます。
現在のバージョンにおいても、単にあなたのプロジェクトに対応するパッケージを追加するだけで、Epoxyを使用することが出来ます。

.NET 7 SDKのCLIテンプレートに対応しています。以下のようなコマンドで、簡単にテンプレートコードをクリーンな状態で試すことができます:

```bash
# テンプレートパッケージをインストール(初回又はバージョンアップ時のみ)
dotnet new -i Epoxy.Templates

# 現在のディレクトリにWPFサンプルコードを展開
dotnet new epoxy-wpf

# ビルド
dotnet build
```

テンプレートコードには、以下のコードが含まれています:

* MVVMのモデルコードを格納する、`Core`プロジェクト。但し中身は空です。
* "Hello Epoxy!"と表示するだけの、非常にシンプルなコードを含むプロジェクト。

注意: テンプレートは .NET 7 を想定しているため、.NET 7 SDKをあらかじめインストールして下さい。
他のバージョンのみの環境(例えば.NET 8/6/5 SDK)では、`TargetFramework`を修正しないと、ビルドに失敗します。

### 現在サポートしているテンプレート一覧
起動後にボタンをクリックすると、The Cat APIから、最新の投稿記事と画像を非同期でダウンロードしながら、
リスト形式で表示するものです。

|`dotnet new`引数|言語|対象|
|:--|:--|:--|
|`epoxy-wpf`|C#, F#|WPFのテンプレートコード|
|`epoxy-avalonia11`|C#, F#|Avalonia 11のテンプレートコード (xplat相当)|
|`epoxy-avalonia`|C#, F#|旧Avaloniaのテンプレートコード|
|`epoxy-opensilver`|C#|OpenSilverのテンプレートコード|
|`epoxy-xamarin-forms`|C#|Xamarin Formsのテンプレートコード|
![EpoxyHello.Wpf](https://github.com/kekyo/Epoxy/raw/main/Images/sample.Wpf.png)

* デフォルトではC#のテンプレートコードが展開されます。F#にする場合は、`dotnet new epoxy-wpf -lang F#`のように、オプションをコマンドラインに加えます。
* Xamarin Formsは、古い形式のMSBuildプロジェクトを使用しています。
* ビルド・実行する場合は、`dotnet build` ではなく、Visual Studioでソリューションを開く必要があります。
* OpenSilverのテンプレートコードは、.NET Frameworkベースのシミュレータプロジェクトが含まれています。
* ビルド・実行する場合は、`dotnet build` ではなく、Visual Studioでソリューションを開く必要があります。
* WebAssemblyとしてChromeやFirefoxなどでホストする場合は、別途プロジェクトが必要です。
* develブランチパッケージを使用できます。dotnet CLI公式には説明されていませんが、`--nuget-source`オプションを使用します: `dotnet new -i Epoxy.Templates::<version> --nuget-source http://nuget.kekyo.online:59103/repository/nuget/index.json --force`
![EpoxyHello.Xamarin.Forms](https://github.com/kekyo/Epoxy/raw/main/Images/sample.Xamarin.Forms.png)

### Visual Studioのウィザードから選択
サンプルコードプロジェクトは、[playgroundディレクトリ](playground/) 、又はF#のサンプルコードは [playground.FSharpディレクトリ](playground.FSharp/)
にあります。

上記テンプレートのインストールを行っておけば、Visual Studioの新規プロジェクト生成でも選択する事が出来ます。
フルスクラッチでEpoxyを導入したい、あるいは既存のプロジェクトにEpoxyを導入したい場合は、
[ステップバイステップでコミットを作成した、Avalonia 11のサンプルリポジトリ](https://github.com/kekyo/Epoxy.Avalonia11.SampleProject) が役に立つかもしれません。

![Template selection dialog](Images/vswizard_ja.png)
### 解説動画があります (YouTube, 日本語のみ):

----
[![Epoxyで C# MVVMアーキテクチャを簡単に実装する話 - 作ってみた 第一回](https://img.youtube.com/vi/LkyrgJbuiQs/0.jpg)](https://www.youtube.com/watch?v=LkyrgJbuiQs)

### サンプルコードの解説
[(再生出来ない場合はこちら)](https://www.youtube.com/watch?v=LkyrgJbuiQs)

起動後にボタンをクリックすると、完全に非同期でダウンロードしながら、リストに結果を追加していきます。
### 導入方法

![EpoxyHello.Wpf](https://github.com/kekyo/Epoxy/raw/main/Images/sample.Wpf.png)
ターゲットとなるGUIフレームワークに対応したNuGetパッケージを導入してください。
Epoxyパッケージは沢山公開されていますが、必要なのは:

![EpoxyHello.Xamarin.Forms](https://github.com/kekyo/Epoxy/raw/main/Images/sample.Xamarin.Forms.png)
* `Epoxy.Avalonia11`
* `Epoxy.Avalonia`
* `Epoxy.WPF`
* `Epoxy.OpenSilver`
* `Epoxy.MAUI`

フルスクラッチでEpoxyを導入したい、あるいは既存のプロジェクトにEpoxyを導入したい場合は、
[ステップバイステップでコミットを作成した、Avalonia 11のサンプルリポジトリ](https://github.com/kekyo/Epoxy.Avalonia11.SampleProject) が役に立つかもしれません。
などのパッケージのみです。
他に `Epoxy.Core.WPF``Epoxy.Build`と言ったパッケージが見つかるかもしれませんが、
これらは上記のパッケージから依存して自動的に使用されます。

注意: `Epoxy.Templates`には、テンプレートプロジェクト定義が含まれていましたが、1.15.0から廃止されました。
これに伴い、Visual Studioのテンプレートウィザードも廃止されています。

----

Expand Down Expand Up @@ -242,7 +195,7 @@ public sealed class MainWindowViewModel
### Modelの実装例

The Cat APIにアクセスする共通コードは、`EpoxyHello.Core` プロジェクトで実装しています。
このプロジェクトは、WPF・Xamarin Forms・Avalonia・OpenSilverのいずれにも依存せず、完全に独立しています。
このプロジェクトは、WPF・Avalonia・OpenSilver・MAUIのいずれにも依存せず、完全に独立しています。

このように、依存性を排除することで、マルチプラットフォーム対応の共通化を行うことが出来ますが、
小規模な開発であれば、`Model`の実装を`ViewModel`と同じプロジェクトに配置してもかまいません
Expand Down Expand Up @@ -285,6 +238,7 @@ Modelの実装は、直接ユーザーインターフェイスを操作する事
|ViewModelインジェクタ|ViewModelに必要なPropertyChangedイベントなどを、ビルド時に自動的に実装出来る機能です。対象のクラスに属性を適用するだけで、煩雑なコードの実装を省略出来ます。|
|ViewModel基底クラス|ViewModelに必要なPropertyChangedイベントなどを、オーソドックスな基底クラスとして提供します。ViewModelインジェクタが適さないシナリオで、使用することが出来ます。|
|Command factory|任意の非同期デリゲートを、ICommandとして利用できるようにします。非同期処理を安全にICommandとして実装出来ます。|
|Fountain/Well|任意のXAMLコントロールのイベントを、バインディング可能にする添付プロパティです。イベントハンドリングを簡単かつ安全にバインディング出来ます。|
|EventBinder|任意のXAMLコントロールのCLRイベントを、ICommandとしてバインディング可能にする添付プロパティです。Commandプロパティが提供されていない任意のイベントを、安全にバインディング出来ます。|
|Anchor/Pile|任意のXAMLコントロールを、一時的かつ安全にViewModelから参照出来るようにします。Anchor/Pileを使用すると、全てのコードビハインドを排除出来るため、MVVMを使用する場合の実装の見通しが良くなります。Messengerパターンとして知られたテクニックも、Anchor/PileでViewModelに集約することが出来ます。|
|ValueConverter|XAMLの値コンバーターの基底クラスを提供します。事前に型判定が行われ、型制約がある状態で実装することが出来ます。|
Expand Down Expand Up @@ -342,8 +296,93 @@ csprojの`PropertyGroup`の`EpoxyBuildEnable`に`False`を指定して下さい

----

### Fountain/Well

`Fountain`/`Well` は、後述の `EventBinder` に代わる、新しいイベントハンドリング機能です。

バインディング出来ないCLRイベントが公開されている場合に、
コードビハインドを一切記述しないで、ViewModel側で簡単にフック出来るようにします。
`RoutedEvent` にも対応しているため、あらゆるイベント処理を全く同じように記述できます。

また、コントロールが表示から切り離されると、イベントのアンフックも自動的に行われるため、
メモリリークを防ぐことが出来ます。

* `Fountain` とは、コントロールのイベントの発生源です。
* `Well` とは、 `Fountain` で発生したイベントを受信する場所で、 `Fountain` とはデータバインディングで結合します。
* イベントハンドラは、 `Well` に対して追加・削除します。

例えば、以下のように、WPFの `Window.Loaded` CLRイベントをバインディング出来ます。
イベントをフックしたいコントロールに、 `Fountain` 添付プロパティを配置してバインディングします:

```xml
<!-- EpoxyのXML名前空間を定義し、FountainをWellとバインディングする -->
<Window xmlns:epoxy="https://github.com/kekyo/Epoxy"
epoxy:Fountain.Well="{Binding MainWindowWell}">

<!-- ... -->
</Window>
```

`ViewModel` 側は、 `Well` を配置しておきます。
`Well` に対してイベント名を指定してハンドラを追加します:

```csharp
// Windowからのイベントを受信するWellを定義する
public Well MainWindowWell { get; } = Well.Factory.Create<Window>();

// ...
// Loadedイベントが発生した場合のハンドラをWellに追加
this.MainWindowWell.Add("Loaded", async () =>
{
// リストに表示する情報をModelから非同期で取得
foreach (var item in await Model.FetchInitialItemsAsync())
{
this.Items.Add(item);
}
});
```

`Well.Add()`メソッドで、イベントに対応するハンドラデリゲートを登録します。
もちろんこのハンドラは、非同期処理対応です。

このメソッドには、イベント名を文字列で指定するオーバーロードと、`RoutedEvent`を指定するオーバーロードがあります。
`RoutedEvent`を指定するオーバーロードを使えば、いわゆる「添付イベント」を受信することも可能です:

```csharp
// ドラッグイベントが発生した場合のハンドラを追加
// (Avaloniaの場合、イベント引数eの型は自動的に決定されます)
this.MainWindowWell.Add(DragDrop.DragEnterEvent, async e =>
{
// (ドラッグイベントの処理)
});
```

Avaloniaでは、 `RoutedEvent` からイベントの引数 `EventArgs` の型が供給されるため、
最も記述量が少なく、タイプセーフ性が維持されます。

* MAUIには、`RoutedEvent`が存在しないため、Epoxyにもこの機能はありません。

一つの `Well` に対して、異なるイベントを同時に追加出来ます。
同じイベント名のハンドラは、同時に一つのみ追加可能です。

#### EventBinderからの移行

`EventBinder` も引き続きサポートされますが、`Fountain`/`Well`に移行すべきかどうか判断したい場合は、以下の表を参考にしてください。

|要素|利点|考慮事項|
|:----|:----|:----|
|XAML|記述量が圧倒的に少ない|いわゆるBehaviorとは構造が異なる|
|バインディング|`Well`をバインディング出来る|`ICommand`がバインディング出来ない|
|ViewModel|CLRイベントだけではなく、`RoutedEvent`もフック出来る。Avaloniaではハンドラ引数型が自動的に決定される|`ICommand`を使用していない|
|リフレクション|将来的にリフレクションフリーを実現する構造|現在はリフレクションを使用。`EventBinder`は常にリフレクションを使用。|

----

### EventBinder

注意:より便利な `Fountain`/`Well` 機能が追加されました。新規に使用する場合はそちらをお勧めします。

`EventBinder`は、バインディング出来ないイベントが公開されている場合に、`Command`としてバインディング可能にします。
この機能により、イベントハンドラを記述するために、やむを得ずコードビハインドを書くと言う手法を回避できます。

Expand Down Expand Up @@ -388,11 +427,11 @@ this.Ready = Command.Factory.Create<EventArgs>(async _ =>
`Command.Factory.Create<T>`のジェネリック引数には、イベントの第二引数(通常EventArgsを継承したクラス)を指定します。
イベントの引数が必要でない場合は、非ジェネリックメソッドを使う事も出来ます。

補足1: WPFやXamarin Formsでは`Behavior``Trigger`で同じことを実現できますが、
補足1: WPFやMAUIでは`Behavior``Trigger`で同じことを実現できますが、
追加のパッケージが必要になることと、汎用的に設計されているため、やや複雑です。
`EventBinder`を使うことで、同じ記法でシンプルに記述できる利点があります。

補足2: UWP環境(Xamarin FormsのUWPビルドを含む)では、対象のイベントは以下のようなシグネチャである必要があります:
補足2: UWP環境(MAUIのUWPビルドを含む)では、対象のイベントは以下のようなシグネチャである必要があります:

```csharp
// EventBinderでバインディング可能なイベント
Expand Down Expand Up @@ -787,6 +826,11 @@ Apache-v2

## History

* 1.15.0:
* 新しいイベントハンドリング機能として、 `Fountain/Well` を追加。
* Xamarin Formsを廃止。
* テンプレートプロジェクトを廃止。
* まだしばらくは新規プロジェクト生成として機能すると思いますが、更新されません。
* 1.14.0:
* Avalonia 11で、XAMLからEpoxyを参照する際の名前空間にURLを指定可能にしました。
`xmlns:epoxy="https://github.com/kekyo/Epoxy"` のように指定できます。
Expand Down
Loading

0 comments on commit e31c50c

Please sign in to comment.