在UI线程中触发自定义事件

时间:2014-08-20 20:22:13

标签: c# delegates thread-safety

下面的示例运行正常,但我希望Complete事件在UI线程中触发其事件处理程序。我不希望HasCompleted()担心检查它是否在UI线程上。应始终在UI线程上调用HasCompleted()的调用。我该怎么做?

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        var game = new Game();
        game.Complete += HasCompleted;
        game.Load();
    }

    private void HasCompleted()
    {
        if (label1.InvokeRequired)
        {
            label1.BeginInvoke(new Action(() => label1.Text = "complete"));
        }
        else
        {
            label1.Text = "complete";
        }
    }
}

public class Game
{
    public Game()
    {

    }

    public event MethodInvoker Complete;

    public void Load()
    {
        var task = new Task(new Action(() =>
            {
                Thread.Sleep(500);
                OnComplete();
            }));
        task.Start();
    }

    private void OnComplete()
    {
        if (Complete != null)
        {
            Complete();
        }
    }
}

1 个答案:

答案 0 :(得分:2)

在创建Game对象时捕获当前同步上下文,并使用该对象将事件封送到首次创建对象时的当前上下文:

public class Game
{
    private SynchronizationContext context;
    public Game()
    {
        context = SynchronizationContext.Current ??
            new SynchronizationContext();
    }

    public MethodInvoker Complete;

    public void Load()
    {
        //...
    }

    private void OnComplete()
    {
        if (Complete != null)
        {
            context.Post(_ => Complete(), null);
        }
    }
}