囫囵吞桃的个人博客 Home

打包一个简单Python程序到C#WPF

#技术笔记 #博客园 #Csharp

在本篇文章中,演示了使用IronPython,如何在一个C#WPF程序中执行python函数。 为了简单起见,这里的Python函数的功能是传入两个double,并返回它们的和。 读者仅需稍加修改,融会贯通,即可使用此方法将Python函数打包成较为精美的WPF程序。 但是这个方法仍有缺陷。 原因在于IronPython与常用的Python解释器不同,是建立在.NET上的一种Python的实现。可能不支持某些第三方库。也可能不支持较新的Python语法。其运行效率也有所不同。

如有错误,欢迎批评与指正!

1.创建WPF项目

![Pasted image 20260213050826.png](/api/assets/附件/Pasted image 20260213050826.png?w=1558&h=954)

2.添加IronPython到依赖

右键依赖项,点击关机NuGet程序包,搜索IronPython并安装 ![Pasted image 20260213050831.png](/api/assets/附件/Pasted image 20260213050831.png?w=1144&h=733)

3.绘制GUI

用VS自带的编辑器绘制GUI,添加三个TextBox和一个Button 计划上面的两个TextBox用作输入,按下按钮后在下面的TextBox输出结果 ![Pasted image 20260213050836.png](/api/assets/附件/Pasted image 20260213050836.png?w=1296&h=897)

将按钮和TextBox的Name如下设置,上面两个TextBox分别是TextBox1和TextBox2,下面的TextBox是TextBox3,按钮则为CalButton ![Pasted image 20260213050844.png](/api/assets/附件/Pasted image 20260213050844.png?w=709&h=381)

4.添加Python代码

![Pasted image 20260213050850.png](/api/assets/附件/Pasted image 20260213050850.png?w=1773&h=847) 在工作目录下创建文件夹src,在其中创建文件pyCal.py 代码内容如下:

def MyAdd(a,b):
    return a+b    ```
用于实现简单的二元求和操作

在左侧的PyCal.py右键,点击属性,在右侧的属性窗口处,设置“复制到输出目录”为“始终复制”
![](https://i-blog.csdnimg.cn/direct/e2376e7af1ef41b08a3c0da27ca5de52.png)

### 5.编写按钮Click后执行的方法
在GUI设计界面双击按钮,Visual Studio自动生成了一个框架
![](https://i-blog.csdnimg.cn/direct/d667603861a3467b8b30c0b7b2c13bc1.png)

先在文件头部加上

using IronPython.Hosting; using Microsoft.Scripting.Hosting;```

在接下来的程序中,将要用到ScriptEngine和ScriptScope对象来操作Python脚本,先在主类的头部先声明这两个变量。

ScriptEngine engine;
ScriptScope scope;```
![](https://i-blog.csdnimg.cn/direct/e15101727d3140c786914cfba1f21789.png)

在入口方法MainWindow()处,初始化这两个变量

engine = Python.CreateEngine(); scope = engine.CreateScope();``` 这两行代码的意思是通过Python类的静态方法CreateEngine()初始化脚本引擎,再通过这个引擎来创建脚本作用域。

脚本地址是 ./src/pyCal.py

为了能够适应不同环境下路径格式的不同(Linux下分隔符用/ Windows下用\),故调用方法System.IO.Path.Combine()

该方法可以将多个表示路径的字符串,根据当前系统的不同,选择用/或\来分隔各个字符串,返回组合后的字符串。

string scriptPath = System.IO.Path.Combine( "src", "pyCal.py");```

engine.ExecuteFile(scriptPath, scope);``` 运行脚本,传入两个参数,一个是刚刚生成的路径字符串scriptPath,一个是刚刚生成的作用域对象scope。 接下来开始编写点击按钮后执行的方法。 先初始化两个变量a,b,分别来接受两个TextBox传入的数字。 用double.TryParse()方法来将TextBox中的文本转换成double,如果失败,这个方法将返回false。 两个TextBox中任意一个转换失败,用消息弹框提示Wrong Input!

double.TryParse()方法用于将字符串转换为double类型,传入两个参数,一个是要转换的字符串,一个是用于接收转换结果的变量,此变量必须是out变量。如果转换成功,返回true,否则返回false(布尔类型)。类似地int也有这样的用法。

if (double.TryParse(TextBox1.Text,out a)&&double.TryParse(TextBox2.Text,out b))
{

}
else
{
    MessageBox.Show("Wrong Input!");
}```
用动态变量PyAddFun来管理脚本作用域中的Python函数""MyAdd
再用double变量result接收计算结果
用第三个文本框显示结果
![](https://i-blog.csdnimg.cn/direct/2c51012c3b154909b8a8b0e81b98c973.png)
 代码部分完整代码如下:

using System.Windows; using IronPython.Hosting; using Microsoft.Scripting.Hosting;

namespace MyApp { ///

/// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { ScriptEngine engine; ScriptScope scope; public MainWindow() { InitializeComponent();

        engine = Python.CreateEngine();
        scope = engine.CreateScope();

        string scriptPath = System.IO.Path.Combine( "src", "pyCal.py");

        engine.ExecuteFile(scriptPath, scope);

    }

    private void CalButton_Click(object sender, RoutedEventArgs e)
    {

        double a, b;

        if (double.TryParse(TextBox1.Text,out a)&&double.TryParse(TextBox2.Text,out b))
        {
            dynamic PyAddFun = scope.GetVariable("MyAdd");
            double result = PyAddFun(a, b);
            TextBox3.Text = $"{result}";

        }
        else
        {
            MessageBox.Show("Wrong Input!");
        }

        
    }
}

}```

6.发布程序

经过调试,程序能够正常运行  右键项目(左侧箭头处),再点击发布

选择文件夹 再选择文件夹 填入想要存放打包后程序的位置,也可以选择默认位置

弹出提示成功的窗口,关闭后,点击 显示所有设置 进行进一步的设置 目标运行时 指打包出来的程序的运行环境。 如果想要程序能够运行在一般的32位或64位windows电脑上,可以选择win-x86 设置完毕后保存 点击发布,即可生成程序 完成后,点击 导航 ,即可看到生成的程序 双击下面那个exe,即可运行程序 由于在第四步将Python代码的“复制到输出目录”为“始终复制”,在调试和发布程序时,会被自动地复制过来。  接下来,将这整个文件夹的内容(图片能看到的所有内容),整体迁移到电脑的其他位置,或者发给其他人,应该都能正常运行(前提是安装了对应版本的.Net Runtime) 如果没有安装,windows会跳出一个弹窗来提示安装。 点进去会弹出一个网页,根据这个网页的指引下载并安装即可。