Cysharp/MessagePipe を試してみた。

github.com

tech.cygames.co.jp

感想

ブログにも書いてある通り prism の eventAggregator より速いので、今後は prism の代わりにこっちを使ってもいいかなぁと思いました。

App.xaml

<Application x:Class="MessagePipeTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MessagePipeTest"
             Startup="Application_Startup"
             >
    <Application.Resources>
         
    </Application.Resources>
</Application>

App.cs

using System;
using System.Windows;
using MessagePipe;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace MessagePipeTest2
{
    public partial class App : Application
    {
        IHost host;

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            host = CreateHostBuilder().Build();

            var vm = host.Services.GetRequiredService<MainWindowVM>();
            var w = host.Services.GetRequiredService<MainWindow>();

            w.DataContext = vm;
            w.Closed += W_Closed;
            w.Show();

            host.RunAsync();
        }

        private void W_Closed(object sender, EventArgs e)
        {
            // Windowをクローズしてもすぐにワーカーが終了しないので強制的に終了させる
            host.Dispose();
        }

        static IHostBuilder CreateHostBuilder()
        {
            return Host.CreateDefaultBuilder()
                .ConfigureServices((ctx, services) =>
                {
                    services.AddMessagePipe();
                    services.AddHostedService<Worker>();
                    services.AddSingleton<MainWindowVM>();
                    services.AddSingleton<MainWindow>();
                });
        }
    }
}

MainWIndow.xaml

<Window x:Class="MessagePipeTest2.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:MessagePipeTest2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <TextBlock Text="{Binding Value}" />
        <TextBox Background="Gray" TextWrapping="Wrap" VerticalScrollBarVisibility="Visible" Height="400"
                 Text="{Binding Text}"
                 TextChanged="tbox1_TextChanged"/>
    </StackPanel>
</Window>

MainWIndow.cs

using System;
using MessagePipe;
using Prism.Mvvm;

namespace MessagePipeTest2
{
    class MainWindowVM : BindableBase
    {
        private int _value;
        public int Value
        {
            get { return _value; }
            set { SetProperty(ref _value, value); }
        }

        private string _text;
        public string Text
        {
            get { return _text; }
            set { SetProperty(ref _text, value); }
        }

        ISubscriber<MyEvent> subscriber;
        readonly IDisposable disposable;

        public MainWindowVM(ISubscriber<MyEvent> subscriber)
        {
            this.subscriber = subscriber;

            var bag = DisposableBag.CreateBuilder();

            this.subscriber.Subscribe(x =>
            {
                Value = x.Value;
                Text = x.Text;
            }).AddTo(bag);

            disposable = bag.Build();
        }

        void Close()
        {
            disposable.Dispose();
        }
    }
}

MainWindowVM

using System;
using MessagePipe;
using Prism.Mvvm;

namespace MessagePipeTest2
{
    class MainWindowVM : BindableBase
    {
        private int _value;
        public int Value
        {
            get { return _value; }
            set { SetProperty(ref _value, value); }
        }

        private string _text;
        public string Text
        {
            get { return _text; }
            set { SetProperty(ref _text, value); }
        }

        ISubscriber<MyEvent> subscriber;
        readonly IDisposable disposable;

        public MainWindowVM(ISubscriber<MyEvent> subscriber)
        {
            this.subscriber = subscriber;

            var bag = DisposableBag.CreateBuilder();

            this.subscriber.Subscribe(x =>
            {
                Value = x.Value;
                Text = x.Text;
            }).AddTo(bag);

            disposable = bag.Build();
        }

        void Close()
        {
            disposable.Dispose();
        }
    }
}

MyEvent.cs

namespace MessagePipeTest2
{
    public class MyEvent
    {
        public int Value { get; set; }

        public string Text { get; set; }
    }
}

Worker.cs

using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using MessagePipe;

namespace MessagePipeTest2
{
    class Worker : BackgroundService
    {
        IPublisher<MyEvent> publisher;

        public Worker(IPublisher<MyEvent> publisher)
        {
            this.publisher = publisher;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            int i = 0;
            string s = "";
            while (!stoppingToken.IsCancellationRequested)
            {
                publisher.Publish(new MyEvent()
                {
                    Value = i,
                    Text = s,
                });
                i++;
                s += DateTime.Now.ToString() + "\n";
                await Task.Delay(1, stoppingToken);
            }
        }
    }
}