关于python:使用IronPython控制C#Winforms GUI

Controlling a C# Winforms GUI with IronPython

因此,我使用C#在Visual Studio中制作了Winforms GUI,但是对于我正在从事的项目,我希望大多数代码都用Python编写。我希望用python编写"引擎"(出于可移植性),然后使应用程序接口成为我可以交换的东西。

我将C#项目编译为.dll,并能够将这些类导入IronPython脚本中并正常启动GUI。

问题在于,除非我将其放入单独的线程中,否则运行GUI会停止执行Python脚本。但是,如果我将GUI放在一个单独的线程中,并尝试使用原始的python线程来更改状态信息,则会收到关于从与创建它的线程不同的线程修改控件的异常。

是否有任何与GUI线程通信的好方法或完成我试图做的事情的方法?

GUI的C#驱动程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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()

将所有内容放置在事件处理程序中对Program.RunGUI()的调用之后。

C#:

1
2
3
4
5
6
7
8
9
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:

1
2
3
4
5
6
7
8
def onload(sender, args):
    time.sleep(2)
    Program.SetState(state)
    raw_input()  

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


控件具有线程关联性,只能由创建它们的线程访问。
有一个BackgroundWorker对象可以很好地处理线程之间的数据传递。


如果要从GUI线程以外的线程中修改GUI,则必须使用Invoke方法。