WPFでChannelを使ったワーカーのデモプログラム

コンピュータ

ワーカーのデモプログラム

ソースコード

ファイル名:WpfChannelWorker.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net10.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

</Project>

ファイル名:CounterWorker.cs

using System.Threading.Channels;

namespace WpfChannelWorker;

// ==========================================
// カウントアップ専用ワーカー
// ==========================================
public sealed class CounterWorker
{
    // -------- メッセージ --------
    private record Request(TaskCompletionSource<int> Completion);

    // -------- リクエストキュー --------
    private readonly Channel<Request> _channel =
        Channel.CreateUnbounded<Request>();

    // -------- ワーカー内部状態 --------
    private int _counter = 0;

    public CounterWorker()
    {
        // 常駐ワーカー起動
        _ = Task.Run(WorkerLoop);
    }

    // ==========================================
    // UI から呼ぶ唯一の API
    // ==========================================
    public async Task<int> CountUpAsync()
    {
        var tcs = new TaskCompletionSource<int>();

        await _channel.Writer.WriteAsync(
            new Request(tcs));

        return await tcs.Task;
    }

    // ==========================================
    // ワーカー本体(単一スレッド Actor)
    // ==========================================
    private async Task WorkerLoop()
    {
        await foreach (var req in _channel.Reader.ReadAllAsync())
        {
            // 疑似的な重い処理
            await Task.Delay(300);

            _counter++;

            req.Completion.SetResult(_counter);
        }
    }
}

ファイル名:MainWindow.xaml.cs

using System.Windows;

namespace WpfChannelWorker;

public partial class MainWindow : Window
{
    private readonly CounterWorker _worker = new();

    public MainWindow()
    {
        InitializeComponent();

        Btn.Click += Btn_Click;
    }

    private async void Btn_Click(object sender, RoutedEventArgs e)
    {
        int value = await _worker.CountUpAsync();
        Btn.Content = value.ToString();
    }
}

ファイル名:MainWindow.xaml

<Window x:Class="WpfChannelWorker.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:WpfChannelWorker"
        mc:Ignorable="d"
        Title="Channel Worker"
        FontSize="20"
        Height="200" Width="300">
    <Grid>
        <Button x:Name="Btn"
                Content="0"
                Width="140"
                Height="40"/>
    </Grid>
</Window>

実行例

ボタンを押すと表示されている数値がカウントアップされます。


コメント