从其他线程更改按钮颜色

时间:2012-10-09 06:54:59

标签: c# multithreading

在我的c#程序中,我在主(UI)线程中创建了一堆按钮。然后我启动一个运行方法Timeline()的计时器。现在我希望在Timeline()方法运行时更改按钮的外观。但我不允许访问对象,因为它们归主线程所有。我该如何解决这个问题?

错误:The calling thread cannot access this object because a different thread owns it.

我发现Dispatcher disp = Dispatcher.CurrentDispatcher;有一个Invoke()方法,但我不确定这是不是正确的方法,我无法让它工作。

以下是我的代码的一部分:

    private static SurfaceButton[,] buttons = new SurfaceButton[dimensionBeats, dimensionsNotes];

    public SurfaceWindow1()
    {
        try
        {
            InitializeComponent();
        }
        catch (Exception ex)
        {
        }


        LoadAudioContent();
        // Add handlers for Application activation events
        AddActivationHandlers();


        InitializeButtons();

        try
        {
            t = new Timer(Timeline, null, 1, dimensionBeats*500);
        }
        catch (Exception e)
        {

        } 
    }

    private void InitializeButtons()
    {
        for (int i = 0; i < 8; i++)
        {
            for (int j = 0; j < 6; j++)
            {
                SurfaceButton btn = new SurfaceButton();
                //btn.Content = files[j].Substring(0,1);
                btn.Name = "a" +i + j;
                btn.Width = 120;
                btn.Height = 120;
                btn.ContactEnter+=StartSound;
                btn.ContactLeave+=StopSound;
                btn.Opacity = 0.01;
                btn.ClickMode = ClickMode.Release;

                buttons[i,j] = btn;

                // add the newly generated button to the correct column (left to right one panel per column)
                switch (i)
                {
                    case 0:
                        rowPanel0.Children.Add(btn);
                        break;
                    case 1:
                        rowPanel1.Children.Add(btn);
                        break;
                    case 2:
                        rowPanel2.Children.Add(btn);
                        break;
                    case 3:
                        rowPanel3.Children.Add(btn);
                        break;
                    case 4:
                        rowPanel4.Children.Add(btn);
                        break;
                    case 5:
                        rowPanel5.Children.Add(btn);
                        break;
                    case 6:
                        rowPanel6.Children.Add(btn);
                        break;
                    case 7:
                        rowPanel7.Children.Add(btn);
                        break;
                }
            }
        }
    }


    private void Timeline(Object state)
    {     

        for (int i = 0; i < pressed.GetLength(0); i++)
        {
            sendRequest(url, postMethod, tabelId, buttsToString(butts));

            for (int j = 0; j < pressed.GetLength(1); j++)
            {
                if (pressed[i,j])
                {
                    buttons[i, j].Background = Brushes.Red;
                }
            }
            Thread.Sleep(500);
            for (int j = 0; j < pressed.GetLength(1); j++)
            {
                buttons[i, j].Background = Brushes.White;
            }
        }

4 个答案:

答案 0 :(得分:2)

您需要使用Invoke/BeginInvoke将更新转发到GUI线程:

int i1 = i; // local copies to avoid closure bugs
int j1 = j;
buttons[i1, j1].Dispatcher.BeginInvoke(
    ((Action)(() => buttons[i1, j1].Background = Brushes.Red)));

答案 1 :(得分:1)

你就是这样做的 -

Button1.Invoke(new MethodInvoker(delegate {
// Executes the following code on the GUI thread.
Button1.BackColor="Red";}));

答案 2 :(得分:0)

尝试使用

包装对按钮或整个(环绕它)的访问
Application.Current.Dispatcher.BeginInvoke((ThreadStart)delegate
{
    // TODO: Implement task to do on main thread
});

必须始终在主线程上访问控件。

答案 3 :(得分:0)

是的,需要使用Invoke方法。它在与Dispatcher关联的线程上同步执行指定的委托。