Skip to content

RRQM/Baboon

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

82 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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);

About

This is a foundational library for lightweight plugin development in WPF and WinForms. It includes built-in modular loading, modular logging, modular IOC registration, as well as essential Command and EventTrigger for WPF MVVM development.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages