用IronPython控制C# Winforms GUI
我在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)