WPFのクラスライブラリを作成し、WPFアプリケーションのプロジェクトとConsoleアプリケーションのプロジェクトから参照するソリューションを作成するスクリプトを作成しました。
dotnet.exeでwinformsの単体テスト(mstest)のプロジェクト作成
dotnet.exeで単体テスト(mstest)を実施する為のプロジェクトの作成方法を調べてみました。 プロジェクトの作成 // ソリューション名:QQQ // WinFormsプロジェクト名:QQQ.Winform // 単体テストプロジ...
WPFのライブラリをConsoleプロジェクトから呼び出す
WPFのBitmapImageオブジェクトを使って画像ファイルの加工するプログラムを作りたいのですが、バッチ処理をする場合GUIは必要ないのでコンソールアプリとして作成したい。 WinFomrsなどで使われるBitmapオブジェクトの場合C...
スクリプト
スクリプト名:Create-WPFSolution.ps1
<#
.SYNOPSIS
WPFプロジェクトを含むソリューションを作成
.DESCRIPTION
WPFのアプリケーション、ライブラリとコンソールプロジェクトを作成します。
アプリケーションにはView
.EXAMPLE
mkdir ソリューション名
cd ソリューション名
Create-WPFSolution.ps1
#>
$ErrorActionPreference = "STOP" # エラーが発生した場合スクリプトを停止する。
$SolutionName = Split-Path (Get-Location).Path -Leaf
$result =Read-Host "Do you want to create a ${SolutionName} solution?(Y/N)"
if ($result.ToUpper() -ne "Y") {
Exit
}
dotnet new sln --name $SolutionName # ソリューションの作成
dotnet new wpflib --name "${SolutionName}.WPFLib" # WPF クラスライブラリ作成
cd "${SolutionName}.WPFLib"
dotnet sln "..\${SolutionName}.sln" add "${SolutionName}.WPFLib.csproj"
$sourceCode = @"
using System;
namespace ${SolutionName}.WPFLib
{
public class Class1
{
public const string CLASS_NAME = "Class1";
}
}
"@
$outFile = Join-Path (Get-location).Path "Class1.cs"
$writer = New-Object System.IO.StreamWriter($outFile, $false, [System.Text.Encoding]::GetEncoding("utf-8"))
$writer.WriteLine($sourceCode)
$writer.Close()
cd ..
dotnet new wpf --name "${SolutionName}.WPF" # WPFプロジェクトの作成
cd "${SolutionName}.WPF"
dotnet sln "..\${SolutionName}.sln" add "${SolutionName}.WPF.csproj"
dotnet add reference "..\${SolutionName}.WPFLib"
dotnet add package Microsoft.Xaml.Behaviors.Wpf
dotnet add package ReactiveProperty.WPF
# ViewModel
$MainWindowViewModel = @"
using System.Diagnostics;
using System;
using System.ComponentModel;
using Reactive.Bindings;
using Reactive.Bindings.Extensions;
using System.Reactive.Disposables;
namespace ${SolutionName}
{
public class MainWindowViewModel : INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
if (PropertyChanged is null) return;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
private CompositeDisposable Disposable { get; } = new CompositeDisposable();
public ReactiveProperty<string> Title { get; private set; }
public MainWindowViewModel()
{
PropertyChanged += (o, e) => {};
string className = Sample01.WPFLib.Class1.CLASS_NAME;
Title = new ReactiveProperty<string>(className).AddTo(this.Disposable);
}
public void Dispose()
{
Debug.WriteLine("Dispose()");
Disposable.Dispose();
}
}
}
"@
$outFile = Join-Path (Get-location).Path "MainWindowViewModel.cs"
$writer = New-Object System.IO.StreamWriter($outFile, $false, [System.Text.Encoding]::GetEncoding("utf-8"))
$writer.WriteLine($MainWindowViewModel)
$writer.Close()
# ViewModelCleanupBehavior
$ViewModelCleanupBehavior = @"
using System.Xml;
using System.Xml.Schema;
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.ComponentModel;
namespace ${SolutionName}
{
public class ViewModelCleanupBehavior : Behavior<Window>
{
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.Closed += this.WindowClosed;
}
private void WindowClosed(object? sender, EventArgs e)
{
(this.AssociatedObject.DataContext as IDisposable)?.Dispose();
}
protected override void OnDetaching()
{
base.OnDetaching();
this.AssociatedObject.Closed -= this.WindowClosed;
}
}
}
"@
$outFile = Join-Path (Get-location).Path "ViewModelCleanupBehavior.cs"
$writer = New-Object System.IO.StreamWriter($outFile, $false, [System.Text.Encoding]::GetEncoding("utf-8"))
$writer.WriteLine($ViewModelCleanupBehavior)
$writer.Close()
# XAML
$inFile = Join-Path (Get-location).Path "MainWindow.xaml"
$xmlDoc = [System.Xml.XmlDocument](Get-Content -Encoding UTF8 -Raw $inFile)
$ns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
$nslocal = "clr-namespace:${SolutionName}"
$nsi = "clr-namespace:Microsoft.Xaml.Behaviors;assembly=Microsoft.Xaml.Behaviors"
$nsinteractivity = "clr-namespace:Reactive.Bindings.Interactivity;assembly=ReactiveProperty.WPF"
$attri = $xmlDoc.CreateAttribute("xmlns:i")
$attri.Value = $nsi
$xmlDoc.Window.Attributes.Append($attri) | Out-Null
$attri2 = $xmlDoc.CreateAttribute("xmlns:interactivity")
$attri2.Value = $nsinteractivity
$xmlDoc.Window.Attributes.Append($attri) | Out-Null
$xmlDoc.Window.setAttribute("Title", "{Binding Title.Value}")
$child = $xmlDoc.CreateElement("Window.DataContext", $ns)
$child2 = $xmlDoc.CreateElement("local:MainWindowViewModel", $nslocal)
$pos = $xmlDoc.getElementsByTagName("Grid")[0]
$dc = $xmlDoc.Window.insertBefore($child, $pos)
$dc.appendChild($child2) | Out-Null
$child3 = $xmlDoc.CreateElement("i:Interaction.Behaviors", $nsi)
$child4 = $xmlDoc.CreateElement("local:ViewModelCleanupBehavior", $nslocal)
$ib = $xmlDoc.Window.insertBefore($child3, $pos)
$ib.appendChild($child4) | Out-Null
$xmlDoc.Save($inFile)
cd ..
dotnet new console --name "${SolutionName}.Console" # コンソールアプリ 作成
cd "${SolutionName}.Console"
# ConsoleプロジェクトのターゲットフレームワークをnetX.XからnetX.X-windowsへ変更
$inFile = Join-Path (Get-location).Path "${SolutionName}.Console.csproj"
$xmlDoc = [System.Xml.XmlDocument](Get-Content -Encoding UTF8 -Raw $inFile)
$target = $xmlDoc.Project.PropertyGroup.TargetFramework
if ($target -match '^net\d.\d$') {
$xmlDoc.Project.PropertyGroup.TargetFramework = ($target + "-windows")
}
$xmlDoc.Save($inFile)
dotnet sln "..\${SolutionName}.sln" add "${SolutionName}.Console.csproj"
dotnet add reference "..\${SolutionName}.WPFLib"
dotnet add package System.Console
$sourceCode = @"
namespace ${SolutionName};
class Program
{
static void Main()
{
string className = ${SolutionName}.WPFLib.Class1.CLASS_NAME;
Console.WriteLine($"ClassName:{className}");
}
}
"@
$outFile = Join-Path (Get-location).Path "Program.cs"
$writer = New-Object System.IO.StreamWriter($outFile, $false, [System.Text.Encoding]::GetEncoding("utf-8"))
$writer.WriteLine($sourceCode)
$writer.Close()
cd ..
使い方
ソリューション用のディレクトリを作成し、そのディレクトリへカレントディレクトリを移動します。
上記スクリプトを実行するとプロジェクトが作成されます。
コメント