文章尾部有完整demo下载
公司封装了几个dll,服务于快捷进程化开发,为此我精简成2个库Cal.Wpf.Part、Cal.Wpf.PartHost
Cal.Wpf.Part 辅助代码
Cal.Wpf.PartHost 子进程依赖的启动程序exe,如果有多个,该程序会生成多个按进程分
先大致看下效果:
一个主进程,2个子进程
下面是所有相关的dll
下面开始针对demo进行使用说明:
1、引用Cal.Wpf.Part.dll、Cal.Wpf.PartHost.exe
2、针对自定义的控件创建**Host.xaml(承载)、**Patrt.cs(辅助类)
3、**Host.xaml 引用 Cal.Wpf.Part.dll,并显示占位
using Cal.Wpf.Part.Remoting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ProcessDemo
{
///
/// UserControlHostControl.xaml 的交互逻辑
///
public partial class CustomUserControlHostControl : UserControl, IDisposable
{
public CustomUserControlHostControl()
{
InitializeComponent();
}
~CustomUserControlHostControl()
{
Dispose();
}
public void Dispose()
{
partHost.Dispose();
}
///
/// 收到进程的事件推送时
///
public event MessageEventHandler ReceiveCommand
{
add
{
partHost.ReceiveCommand += value;
}
remove
{
partHost.ReceiveCommand -= value;
}
}
///
/// 设置在独立进程中运行的控件
///
/// 父窗口句柄
public void InitPartControl(IntPtr parentWindowHandler)
{
partHost.InitPartControl(typeof(CustomUserControlPart), parentWindowHandler);
}
///
/// 发送消息
///
///
public void SendMsg(string msg)
{
partHost.SendCommand(new ProcessMessage()
{
Body = msg,
Command = 1
});
}
}
}
4、 **Patrt.cs实现接口IPart
using Cal.Wpf.Part;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace ProcessDemo
{
public class CustomUserControlPart : IPart
{
///
/// 逻辑主控件
///
private CustomUserControl control;
///
/// 向主进程发消息时
///
public event Cal.Wpf.Part.Remoting.MessageEventHandler SendCommand;
///
/// 进程调用,需要支援释放了
///
///
public void Dispose()
{
if (control != null)
{
control.SendMsg -= Control_SendMsg;
}
}
///
/// 收到主进程消息时
///
///
public void ExecuteCommand(Cal.Wpf.Part.Remoting.ProcessMessage message)
{
if (message == null || message.Body == null) return;
control.SetMsg(message.Body.ToString());
}
///
/// 进程调用,获取当前插件的展示界面
///
///
public FrameworkElement GetPartControl()
{
if (control == null)
{
control = new CustomUserControl();
control.SendMsg += Control_SendMsg;
}
return control;
}
///
/// CustomUserControl 需要先外部进程发送消息时
///
///
///
private void Control_SendMsg(object sender, Tuple e)
{
SendCommand?.Invoke(new Cal.Wpf.Part.Remoting.ProcessMessage()
{
Command = e.Item1,
Body = e.Item2
});
}
public void Initialize()
{
//加载CustomUserControl 之前需要做的事情,可以在这里写,比如加载皮肤dll等...
}
}
}
5、真实的自定义控件再原有的逻辑里,需要处理和主程序的消息通讯,因为当前控件是渲染在子控件上的
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ProcessDemo
{
///
/// CustomUserControl.xaml 的交互逻辑
///
public partial class CustomUserControl : UserControl
{
public CustomUserControl()
{
InitializeComponent();
if (!DesignerProperties.GetIsInDesignMode(this))
{
pid.Text = $"当前进程id:{Process.GetCurrentProcess().Id}";
}
}
///
/// 发送消息时
///
public event EventHandler> SendMsg;
///
/// 发送消息到主进程
///
///
///
private void Button_Click(object sender, RoutedEventArgs e)
{
SendMsg?.Invoke(this, new Tuple(1, msg.Text));
}
///
/// 收到主进程的消息时
///
///
public void SetMsg(string msg)
{
Dispatcher.Invoke(() =>
{
msgstr.Text = $"收到主进程发来的消息:{msg}";
});
}
}
}
6、最后就是在主进程上,把**Host占位,且在恰当的时候初始化子进程即可
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace ProcessDemo
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
if (!DesignerProperties.GetIsInDesignMode(this))
{
pid.Text = $"当前进程id:{Process.GetCurrentProcess().Id}";
hostcontrol.ReceiveCommand += Hostcontrol_ReceiveCommand;
Loaded += MainWindow_Loaded;
}
}
///
/// 窗口加载后
///
///
///
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
//获取当前句柄
var parentWnd = Window.GetWindow(this);
var winHelper = new WindowInteropHelper(parentWnd);
IntPtr parentWindowHandler = winHelper.EnsureHandle();
//初始化子进程
hostcontrol.InitPartControl(parentWindowHandler);
hostcontrol2.InitPartControl(parentWindowHandler);
}
///
/// 当收到子进程发来消息时
///
///
///
private Cal.Wpf.Part.Remoting.ProcessMessage Hostcontrol_ReceiveCommand(Cal.Wpf.Part.Remoting.ProcessMessage message)
{
if (message == null || message.Body == null) return null;
msgstr.Dispatcher.Invoke(() =>
{
msgstr.Text = $"子进程发来消息:{message.Body.ToString()}";
});
return null;
}
///
/// 发给子进程
///
///
///
private void Button_Click(object sender, RoutedEventArgs e)
{
hostcontrol.SendMsg(msg.Text);
}
}
}
有需要完整demo的,也可以异步下载,下面是解决方案摘要