最近一个项目,需要在WPF的页面中实现Python的调用,不用很复杂的Python模块,只使用原生的Python完成一些判断逻辑下的下单即可。
之前也做过类似的项目,但是那是在大神的领导的框架下实现的,为了能兼容Python的第三方模块的调用,使用了CPython,这个实现就很复杂了,具体的原理是在C++,Python和C#三个对象之间做了转换,最终是可以实现了,过程很复杂,需要修改Cpython的源码,这次没有大神的参与,需要自己实现,我选择了简单的IronPython,目前看是可以满足需求的。
使用IronPython就比较简单了,IronPython和C#之间天然就是可以互相调用的。查了一些使用方法之后,开始按照自己的需求实现,主要实现以下几种调用方式,符合我的使用需求,在满足一定的条件之后实现下单。
1,最简单的使用方式,在C#中执行Python的方法
Python脚本
@"results = list()
def GetResults():
results.append('start')
results.append('start')
return results
C#后台代码
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var sourceCode = engine.CreateScriptSourceFromString(formulaEditor.Text);
sourceCode.Execute<object>(scope);
1,直接使用results的列表
var res = scope.GetVariable("results");
IronPython.Runtime.List list = res as IronPython.Runtime.List;
2,通过执行GetResults方法获取到results的结果
var test = scope.GetVariable<Func<object>>("GetResults");
object res = test();
IronPython.Runtime.List list = res as IronPython.Runtime.List;
以上是两种获得返回值的方法,一种是调用方法,一中是直接使用List。
2,要在C#的窗体种执行完Python脚本,并且把结果实时输出到窗体中,我最后选择了事件的调用方式传递
Python代码
def SetResults():
Broadcast('Test')
Broadcast('Start')
Broadcast('Start')
C#代码
private void EventTriggerWindow_Broadcast(string a)
{
Dispatcher.Invoke(() => { OutResults.Add(a); });
}
public delegate void BroadcastEventHander(string a);
public event BroadcastEventHander Broadcast;
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var sourceCode = engine.CreateScriptSourceFromString(formulaEditor.Text);
scope.SetVariable("Broadcast", Broadcast);
sourceCode.Execute<object>(scope);
var test = scope.GetVariable<Func<object>>("SetResults");
Task.Run(() => { test(); });
通过事件Broadcast在Python中实时输入运行结果,现实到C#的窗体控件上
3,想要实现在C#中定义事件,然后在Python中触发事件,具体代码如下
Python脚本
def SendOrder(stkid):
Broadcast(stkid)
def SetResults():
Broadcast('Start')
QuotationSource.Broadcast+=SendOrder
QuotationSource.SubScribe('1000001')
Broadcast('End')
C#代码
定义了一个类
public class QuotationSource
{
public string StkId { get; set; }
public QuotationSource()
{ }
public void SubScribe(string stkId)
{
this.StkId = stkId;
}
public void OnTick()
{
if (Broadcast != null)
Broadcast(StkId);
}
public delegate void BroadcastEventHander(string args);
public event BroadcastEventHander Broadcast;
}
点击按钮的时候触发事件
private void Button_Click_1(object sender, RoutedEventArgs e)
{
quotationSource.OnTick();
}
ScriptEngine engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
var sourceCode = engine.CreateScriptSourceFromString(formulaEditor.Text);
scope.SetVariable("QuotationSource", quotationSource);
scope.SetVariable("Broadcast", Broadcast);
sourceCode.Execute<object>(scope);
var test = scope.GetVariable<Func<object>>("SetResults");
Task.Run(() => { test(); });
这样就实现了Python中执行C#的事件触发
整体项目也会上传,代码写的比较乱,因为是个Demo我也没有整理