■概要
Epoxyを触ってみた。
■環境
- Windows 10
- Visual Studio Community 2019 Version 16.9.2
- .NET 5.0
- Epoxy.Wpf 0.15.0
■プロジェクト構成
■ソース
◇EpoxySample1.csproj
EpoxySample1.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Epoxy.Wpf" Version="0.15.0" />
</ItemGroup>
</Project>
◇MainWindow.xaml
MainWindow.xaml
<Window
x:Class="EpoxySample1.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:conv="clr-namespace:EpoxySample1.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ep="https://github.com/kekyo/Epoxy"
xmlns:local="clr-namespace:EpoxySample1.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:EpoxySample1.ViewModels"
Title="MainWindow"
Width="500"
Height="300"
ResizeMode="CanResizeWithGrip"
mc:Ignorable="d">
<Window.Resources>
<conv:InverseBooleanConverter x:Key="InverseBool" />
</Window.Resources>
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
<ep:EventBinder.Events>
<ep:Event Name="Loaded" Command="{Binding WindowLoaded}" />
</ep:EventBinder.Events>
<Grid Background="WhiteSmoke">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel IsEnabled="{Binding IsBusy, Converter={StaticResource InverseBool}}">
<TextBlock Margin="8,0" Text="パス" />
<!-- 検索するパス -->
<TextBox Margin="8,0" Text="{Binding TargetPath, UpdateSourceTrigger=PropertyChanged}" />
<!-- 検索ボタン -->
<Button
Width="200"
Margin="8"
Padding="0,8"
Command="{Binding SearchCommand}"
Content="検索" />
</StackPanel>
<!-- 指定されたパス直下のフォルダを一覧表示 -->
<ListBox
Grid.Row="1"
Margin="8,8,8,16"
ItemsSource="{Binding PathList}" />
</Grid>
</Window>
◇MainWindowViewModel.cs
MainWindowViewModel.cs
using Epoxy;
using Epoxy.Synchronized;
using System.Collections.ObjectModel;
using System.Windows;
namespace EpoxySample1.ViewModels
{
public sealed class MainWindowViewModel : ViewModel
{
/// <summary>
/// 検索対象パス
/// </summary>
public string? TargetPath
{
get => GetValue();
set
{
SetValue(value);
// 検索コマンドの実行可否 更新
SearchCommand?.ChangeCanExecute();
}
}
/// <summary>
/// 処理中フラグ
/// </summary>
public bool IsBusy
{
get => GetValue();
private set => SetValue(value);
}
/// <summary>
/// 検索結果パス一覧
/// </summary>
public ObservableCollection<string>? PathList
{
get => GetValue<ObservableCollection<string>?>();
private set => SetValue(value);
}
/// <summary>
/// ウィンドウ起動時の処理
/// </summary>
public Command? WindowLoaded
{
get => GetValue();
private set => SetValue(value);
}
/// <summary>
/// 検索コマンド
/// </summary>
public Command? SearchCommand
{
get => GetValue();
private set => SetValue(value);
}
/// <summary>
/// コンストラクタ
/// </summary>
public MainWindowViewModel()
{
CreateCommands();
}
/// <summary>
/// コマンド初期化
/// </summary>
private void CreateCommands()
{
// ウィンドウ起動
WindowLoaded = Command.Factory.CreateSync<RoutedEventArgs>(e =>
{
IsBusy = false;
TargetPath = @"C:\ProgramData";
PathList = new ObservableCollection<string>();
});
// 検索
SearchCommand = CommandFactory.Create(
executeAsync: async () =>
{
IsBusy = true;
PathList?.Clear();
var dir = new Models.Directory(TargetPath ?? "");
await foreach (var item in dir.GetItemsAsync())
{
PathList?.Add(item);
}
IsBusy = false;
},
canExecute: () =>
{
// パスが空のときは無効
return !string.IsNullOrWhiteSpace(TargetPath);
}
);
}
}
}
◇Directory.cs
Directory.cs
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace EpoxySample1.Models
{
public class Directory
{
private readonly string _basePath;
public Directory(string basePath)
{
_basePath = basePath;
}
public async IAsyncEnumerable<string> GetItemsAsync()
{
var dirs = System.IO.Directory.EnumerateDirectories(
_basePath, "*", SearchOption.TopDirectoryOnly);
foreach (var dir in dirs)
{
// すぐ終わらないよう少し待つ
await Task.Delay(100);
// 1つ返す
yield return dir;
}
}
}
}
◇InverseBooleanConverter.cs
InverseBooleanConverter.cs
using Epoxy;
namespace EpoxySample1.Converters
{
/// <summary>
/// bool反転
/// </summary>
public class InverseBooleanConverter : ValueConverter<bool, bool>
{
public override bool TryConvert(bool from, out bool result)
{
result = !from;
// 処理成功したらtrue
return true;
}
}
}