在其他线程wpf中访问ui元素

时间:2013-10-22 22:03:51

标签: c# wpf multithreading

我需要从另一个线程访问TextBoxes应用程序中的WPF,我有一个例外。我知道,每个UI控件和方法Dispatcher都有一个属性BeginInvoke,但我不知道如何从TextBoxes获取值。

所以,这是代码:

  
private void TestConnection_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var task = new Task(() => TryConnect());
                task.Start();
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message); 
            }
        }
        void TryConnect()
        {
            try
            {
                string con_str = "Server=" + Ip.Text + ";Port=" + Port.Text +
                ";Database=hospital;Uid=" + login.Text + 
                ";Pwd=" + password.Text + ";";
                using (MySqlConnection mcon = new MySqlConnection(con_str))
                {
                    mcon.Open();
                    MessageBox.Show("Connection is OK!");
                    mcon.Close();
                }
            }
            catch (MySqlException ex)
            {
                MessageBox.Show(ex.ErrorCode.ToString() + " " + ex.Message);
            }
            catch (Exception exc)
            {
                MessageBox.Show(exc.Message);
            }
        }

2 个答案:

答案 0 :(得分:2)

如果您创建了所需值的副本,那么您应该能够访问它们:

string username = login.Text, password = password.Text, ip = Ip.Text, port = Port.Text;
var task = new Task(() => TryConnect(username, password, ip, port));

void TryConnect(string username, string password, string ip, string port) 
{
    // ...
}

像这样在本地复制值意味着您不需要从后台线程访问UI元素。

答案 1 :(得分:2)

要回答您的问题,请将连接字符串构建移出任务操作:

        private void TestConnection_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            string con_str = "Server=" + Ip.Text + ";Port=" + Port.Text + ";Database=hospital;Uid=" + login.Text + ";Pwd=" + password.Text + ";";

            var task = new Task(() => TryConnect(con_str));
            task.Start();
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message);
        }
    }
    void TryConnect(string con_str)
    {
        try
        {

            using (MySqlConnection mcon = new MySqlConnection(con_str))
            {
                mcon.Open();
                MessageBox.Show("Connection is OK!");
                mcon.Close();
            }
        }
        catch (MySqlException ex)
        {
            MessageBox.Show(ex.ErrorCode.ToString() + " " + ex.Message);
        }
        catch (Exception exc)
        {
            MessageBox.Show(exc.Message);
        }
    }

但是你在这段代码中遇到了很多问题。

  • WPF背后的代码不是“最佳实践” 试着看看这个: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

  • 另一个线程上的MessageBox可能会造成很大的痛苦。

  • 您正在尝试捕获创建任务的异常,这不会捕获在操作中抛出的异常。 试试这个:

        private void TestConnection_Click(object sender, RoutedEventArgs e)
    {
        string con_str = "Server=" + Ip.Text + ";Port=" + Port.Text + ";Database=hospital;Uid=" + login.Text + ";Pwd=" + password.Text + ";";
        var dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
        var task = new Task(() => TryConnect(con_str));
        task.ContinueWith(task1 =>
            {
                //TODO Handle exception
                System.Diagnostics.Trace.WriteLine(task1.Exception);
                //or if you really want an messageBox, pass it back to the ui thread
                dispatcher.Invoke(() => MessageBox.Show(task1.Exception.Message));
    
            }, TaskContinuationOptions.OnlyOnFaulted);
        task.Start();
    }