用IronPython控制C# Winforms GUI

3 投票
3 回答
3938 浏览
提问于 2025-04-16 02:17

我在Visual Studio里用C#做了一个Winforms图形界面,但我现在的项目希望大部分代码用Python来写。我想把“引擎”用Python写,这样更方便移植,然后把应用程序的界面换成我可以随时替换的东西。

我把C#项目编译成了一个.dll文件,然后成功地在IronPython脚本中导入了这些类,并且可以正常启动图形界面。

问题是,运行图形界面会阻止Python脚本的执行,除非我把它放到一个单独的线程里。但是,如果我把图形界面放到一个单独的线程中,而用原来的Python线程去修改状态信息,就会出现一个异常,提示我不能从创建它的不同线程去修改控件。

有没有什么好的方法可以和图形界面的线程进行沟通,或者有什么办法可以实现我想做的事情呢?

这是图形界面的C#驱动代码:

public class Program
{
    private static MainWindow window;

    [STAThread]
    static void Main()
    {
        Program.RunGUI();
    }

    public static void RunGUI()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        window = new MainWindow();
        Application.Run(window);
    }

    public static void SetState(GameState state)
    {
        window.State = state;
    }
}

还有这个Python脚本:

import clr
clr.AddReferenceToFile("TG.Model.dll")
clr.AddReferenceToFile("TG.UI.dll")
from TG.Model import GameState
from TG.UI import Program
import thread
import time


def main():
    print "Hello!"
    state = GameState()
    print state.CharacterName
    print dir(Program)
    thread.start_new_thread(Program.RunGUI, ())
    #Program.RunGUI()
    time.sleep(2)
    Program.SetState(state)
    raw_input()


if __name__ == "__main__":
    main()

3 个回答

0

如果你想在一个不是图形界面线程的线程里修改图形界面,你必须使用Invoke方法。

1

控件有线程亲和性,也就是说,只有创建它们的那个线程才能访问这些控件。为了在不同线程之间传递数据,有一个叫做BackgroundWorker的对象,它可以很好地处理这个问题。

3

把调用 Program.RunGUI() 之后的所有内容放到一个事件处理器里。

C#:

public static void RunGUI(EventHandler onLoad)
{   
    ...

    window = new MainWindow();
    window.Load += onLoad;
    Application.Run(window);
    window.Load -= onLoad; //removes handler in case RunGUI() is called again
}

Python:

def onload(sender, args):
    time.sleep(2)
    Program.SetState(state)
    raw_input()  

def main():
    ...
    Program.RunGUI(onload)

撰写回答