Baboon 3.1.5

dotnet add package Baboon --version 3.1.5
                    
NuGet\Install-Package Baboon -Version 3.1.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Baboon" Version="3.1.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Baboon" Version="3.1.5" />
                    
Directory.Packages.props
<PackageReference Include="Baboon" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Baboon --version 3.1.5
                    
#r "nuget: Baboon, 3.1.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Baboon&version=3.1.5
                    
Install Baboon as a Cake Addin
#tool nuget:?package=Baboon&version=3.1.5
                    
Install Baboon as a Cake Tool

Baboon

一、介绍

这是一个轻量级wpfwinform的插件化开发的基础库。它内置了模块化加载、模块化日志记录、模块化IOC注册、以及开发wpf时的Mvvm必要的CommandEventTrigger

二、安装教程

nuget安装Baboon即可。

Install-Package Baboon

三、使用

3.1 Wpf使用

Wpf安装完成以后,需要在App.xamlApp.xaml.cs中,修改基类继承。

<baboon:BaboonWpfApplication x:Class="Baboon.Wpf.App"
                          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                          xmlns:baboon="clr-namespace:Baboon;assembly=Baboon">
    <Application.Resources />
</baboon:BaboonWpfApplication>

同时需要在App.xaml.cs中,实现抽象类成员。包括注册容器和创建主窗口。

public partial class App : BaboonWpfApplication
{
    protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
    {
        //可以直接注册模块
        //moduleCatalog.Add<SayHelloModule>;
    }

    protected override Window CreateMainWindow(IWindowManager windowManager)
    {
        return windowManager.GetWindow<MainWindow>();
    }

    protected override Task InitializeAsync(AppModuleInitEventArgs e)
    {
        //程序初始化时执行
        //可以在这里注册服务

        //注册单例模式的View和ViewModel
        e.Services.AddSingletonView<MainWindow, MainViewModel>();
        return Task.CompletedTask;
    }

    protected override Task StartupAsync(AppModuleStartupEventArgs e)
    {
        //程序启动时执行
        //可以在这里通过ServiceProvider获取服务
        //this.ServiceProvider.Resolve<MainViewModel>();
        return Task.CompletedTask;
    }
}

3.2 Winform使用

Winform安装完成以后,需要在Program.cs中,修改部分逻辑。

首先,需要新建一个类,继承自BaboonWinformApplication

然后重写CreateMainFormInitializeAsyncStartupAsync

class MyApp : BaboonWinformApplication
{
    protected override Form CreateMainForm(IFormManager formManager)
    {
        return formManager.GetForm<Form1>();
    }

    protected override Task InitializeAsync(AppModuleInitEventArgs e)
    {
        //注意:非必要,不要把Form注册到容器中,不然无法释放内存。
        //添加服务
        //e.Services.AddSingleton<>();
        return Task.CompletedTask;
    }

    protected override Task StartupAsync(AppModuleStartupEventArgs e)
    {
        return Task.CompletedTask;
    }
}

然后在Program.cs中,使用下列代码替换Main方法。

[STAThread]
static void Main()
{
    var myApp = new MyApp();
    myApp.Run();
}

四、使用模块

4.1 创建模块

新建一个库项目,命名为SayHello.Module,添加对Baboon的引用。

然后新建一个类,命名为SayHelloModule,继承自AppModuleBase或实现IAppModule接口。

然后实现基本成员。

public class SayHelloModule : AppModuleBase
{
    public SayHelloModule()
    {
        this.Description = new ModuleDescription("D7F3274A-2526-43FD-B278-099630BDA33E", "SayHello", new Version(1, 0, 0, 0), "RRQM", "test");
    }

    public override ModuleDescription Description { get; }

    protected override Task OnInitializeAsync(IApplication application, AppModuleInitEventArgs e)
    {
        return Task.CompletedTask;
    }

    protected override async Task OnStartupAsync(IApplication application, AppModuleStartupEventArgs e)
    {
        System.Windows.MessageBox.Show("Hello 模块已加载");
    }
}

4.2 发现、加载模块

然后将编译好的dll文件,放入到主运行程序的Modules文件夹下。因为Baboon会自动加载Modules文件夹下的所有模块。

如果你的库项目的名称不是以.Module结尾,则需要在主运行程序中(WpfBaboonWpfApplicationWinformBaboonWinformApplication),重写FindModule方法,注册模块。

protected override bool FindModule(string path)
{
    var name = Path.GetFileNameWithoutExtension(path);
    return name.EndsWith("Module");
}

4.3 直接加载模块

如果你的模块是直接引用的,则可以直接使用。

例如:

 protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
 {
     //可以直接注册模块
     //moduleCatalog.Add<SayHelloModule>;
 }

五、使用IOC

Baboon使用了Microsoft.Extensions.DependencyInjection作为IOC容器。并且规范了使用时机。

5.1 注册服务

在主程序中,或者是模块中,重写InitializeAsync方法。即可注册服务。

protected override Task InitializeAsync(AppModuleInitEventArgs e)
{
    e.Services.AddSingleton<Form1>();
    return Task.CompletedTask;
}

5.2 获取服务

在主程序中,或者是模块中,重写StartupAsync方法。即可获取服务。

protected override Task StartupAsync(AppModuleStartupEventArgs e)
{
    var form1 = e.Services.GetRequiredService<Form1>();
    return Task.CompletedTask;
}

六、主线程切换

Baboon提供了一个简单的线程切换的方法。可以很方便的在子线程中切换到主线程,并执行一些UI操作。

例如: 我们有以下需求: 在主窗体加载事件中,需要使用子线程,执行一些耗时的操作。执行完成后,需要把主窗体的Title修改为“Hello”。

那么在wpf中你只需要这样写:

private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    //切换到子线程
    await Task.Run(async () =>
    {
        //模拟耗时操作
        for (int i = 0; i < 1000; i++)
        {
            Debug.WriteLine(i);
        }

        //切换到主线程
        await MainThreadTaskFactory.SwitchToMainThreadAsync();

        //更新UI
        this.Title = "Hello";
    });
}

Winform中,你只需要这样写:

private async void Form1_Load(object sender, EventArgs e)
{
    //切换到子线程
    await Task.Run(async () =>
    {
        //模拟耗时操作
        for (int i = 0; i < 1000; i++)
        {
            Debug.WriteLine(i);
        }

        //切换到主线程
        await MainThreadTaskFactory.SwitchToMainThreadAsync();

        //更新UI
        this.Text = "Hello";
    });
}

七、Wpf相关操作

7.1 注册时绑定View和ViewModel

Baboon提供了一个简单的方法,来注册ViewViewModel

e.Services.AddSingletonView<MainWindow, MainViewModel>();

7.2 区域导航

Baboon提供了一个简单的区域导航的方法。

首先,需要在主窗体的所需布局中,添加一个ContentControl,命名为contentRoot,作为导航的显示区域。

<ContentControl x:Name="contentRoot"/>

然后,在主窗体的构造函数中,注册区域导航。

public MainWindow(IRegionManager regionManager)
{
    InitializeComponent();
    regionManager.AddRoot("mainRoot",this.contentRoot);
}

然后创建一个基本的ViewViewModel

例如:RegionControlRegionControlViewModel

然后需要注册导航。此处使用tag为“RegionControl”来标识。

e.Services.AddSingletonNavigate<RegionControl, RegionControlViewModel>("RegionControl");

假如,我们想在MainViewModel中导航到RegionControlmainRoot

那只需要在MainViewModel中注入IRegionManager,然后在MainViewModel的构造函数中,导航到RegionControl

public MainViewModel(IRegionManager regionManager)
{
    this.regionManager.RequestNavigate("mainRoot", "RegionControl");
}

7.3 全局资源

每个模块在加载时,可以使用自己领域的资源。但是如果需要把自己的资源分享到全局资源时,那么可以使用Baboon提供的全局资源服务来添加。

例如:

protected override async Task OnStartupAsync(IApplication application, AppModuleStartupEventArgs e)
{
    var resourceService = this.ServiceProvider.GetRequiredService<IResourceService>();
    resourceService.AddResourceDictionary(new ResourceDictionary());
}

八、消息通知

8.1 CommunityToolkit.Mvvm消息通知

Baboon引用了CommunityToolkit.Mvvm,所以可以使用它的消息通知。以下是一个使用 CommunityToolkit.Mvvm 进行消息通知的示例代码,包含消息定义、发送者和接收者的实现。

定义消息类

我们首先定义一个消息类,用于在不同的组件之间传递数据。

// 定义一个消息类,继承自 ValueChangedMessage<string>
// 这里使用泛型,指定消息携带的数据类型为 string
using CommunityToolkit.Mvvm.Messaging.Messages;

// 定义一个自定义消息类,继承自 ValueChangedMessage<string>
// 用于在不同组件之间传递字符串类型的消息
public class CustomMessage : ValueChangedMessage<string>
{
    public CustomMessage(string value) : base(value)
    {
    }
}
实现消息接收者

接下来,我们创建一个消息接收者类,该类将订阅 CustomMessage 并处理接收到的消息。

// 定义一个消息接收者类
public class MessageReceiver
{
    public MessageReceiver(IMessenger messenger)
    {
        // 注册消息接收处理方法
        messenger.Register<CustomMessage>(this, (r, m) =>
        {
            // 处理接收到的消息
            Console.WriteLine($"Received message: {m.Value}");
        });
    }
}
实现消息发送者

然后,我们创建一个消息发送者类,该类将发送 CustomMessage

// 定义一个消息发送者类
public class MessageSender
{
    private readonly IMessenger _messenger;

    public MessageSender(IMessenger messenger)
    {
        _messenger = messenger;
    }

    public void SendMessage(string message)
    {
        // 发送自定义消息
        _messenger.Send(new CustomMessage(message));
    }
}
在需要的方法中使用消息通知

最后,在方法中创建消息发送者和接收者,并发送消息。

static void Test()
{
    // 创建一个全局的 Messenger 实例
    var messenger = WeakReferenceMessenger.Default;

    // 创建消息接收者实例
    var receiver = new MessageReceiver(messenger);
    // 创建消息发送者实例
    var sender = new MessageSender(messenger);

    // 发送消息
    sender.SendMessage("Hello, Messenger!");
}
运行结果

当你运行上述代码时,控制台将输出:

Received message: Hello, Messenger!

这表明消息成功从发送者传递到了接收者。

8.2 使用TouchSocket.Core应用信使

说明

应用信使是在进程内的,行使注册和触发功能的组件。可代替事件,可跨越程序集,可依赖倒置

注册

下列演示时,是使用AppMessenger.Default默认实例,实际上,用户可以自己新实例化的AppMessenger

注册实例

首先让类实例实现IMessageObject接口,然后在实例类中声明异步公共实例方法,并使用AppMessage特性标记。

然后一般情况下,建议在构造函数中,注册消息。

public class MessageObject : IMessageObject
{
    public MessageObject()
    {
        AppMessenger.Default.Register(this);
    }

    [AppMessage]
    public Task<int> Add(int a, int b)
    {
        return Task.FromResult(a + b);
    }

    [AppMessage]
    public Task<int> Sub(int a, int b)
    {
        return Task.FromResult(a - b);
    }
}

对于实例类,如果构造函数中,没有注册消息,那么在构造函数之后,也可以使用其实例注册消息。

var messageObject = new MessageObject();
AppMessenger.Default.Register(messageObject);
注册静态方法

注册静态方法,只需在类中直接声明异步公共实例方法,并使用AppMessage特性标记即可。

public static class MessageObject : IMessageObject
{
    [AppMessage]
    public static Task<int> StaticAdd(int a, int b)
    {
        return Task.FromResult(a + b);
    }
}

使用RegisterStatic进行注册

AppMessenger.Default.RegisterStatic<MessageObject>();
触发

触发时,泛型类型,即时返回值类型。

int add = await appMessenger.SendAsync<int>("Add", 20, 10);

int sub =await appMessenger.SendAsync<int>("Sub", 20, 10);
Product Compatible and additional computed target framework versions.
.NET net6.0-windows7.0 is compatible.  net7.0-windows was computed.  net8.0-windows was computed.  net9.0-windows was computed.  net10.0-windows was computed. 
.NET Framework net462 is compatible.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.1.5 161 4/29/2025
3.1.4 148 3/30/2025
3.1.3 170 3/12/2025
3.1.2 210 3/8/2025
3.1.1 220 3/6/2025
3.1.0 219 3/6/2025
3.0.0 107 2/21/2025
2.0.3 106 2/21/2025
2.0.1 108 2/20/2025
2.0.0 115 2/14/2025
1.2.0 133 10/21/2024
1.1.3 106 8/24/2024
1.1.2 119 3/8/2024
1.1.1 111 3/1/2024
1.1.0 217 11/13/2023
1.0.0 109 9/26/2023
1.0.0-beta 88 9/22/2023