C#WPF / XAML从任何地方/任何线程帮助访问TextBox

时间:2011-03-17 18:51:54

标签: c# wpf textbox backgroundworker

我正试图从我的程序中的任何地方发布到一个文本框,无论它在哪个线程或者拥有它的对象等等......

我在下面尝试了一些事情,一切都行不通。

尝试1:清理中不存在tbLog,另一个线程拥有它。

namespace MyProgram 
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Cleaning clng = new Cleaning(); 
        }

        public buttonStartTasks_Click(object sender, RoutedEventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();

            worker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                Dispatcher.Invoke(new Action(delegate { tbLog.Text += "Starting to clean"; }));
                clng.cleanRoom(); 
            }

            worker.RunWorkerAsync();
        }
    }
}

namespace Tasks
{
    public class Cleaning
    {
        public void cleanRoom()
        {
            tbLog.Text += "Dusting...."; 
            Thread.Sleep(50000); //work sim
            tbLog.Text += "Sweeping...."; 
            Thread.Sleep(50000); //work sim
            tbLog.Text += "Hanging up clothes...."; 
            Thread.Sleep(50000); //work sim
            tbLog.Text += "Organize shelves...."; 
            Thread.Sleep(50000); //work sim
            tbLog.Text += "Remaining odds and ends...."; 
            Thread.Sleep(50000); //work sim
        }
    }
}

尝试2:我试图将tbLog传递给Cleaning。我收到此错误“调用线程无法访问此对象,因为另一个线程拥有它”。这是有道理的。

namespace MyProgram 
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Cleaning clng = new Cleaning(tbLog); 
        }

        public buttonStartTasks_Click(object sender, RoutedEventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();

            worker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                Dispatcher.Invoke(new Action(delegate { tbLog.Text += "!!! Starting to clean !!!"; }));
                clng.cleanRoom(); 
            }

            worker.RunWorkerAsync();
        }
    }
}

namespace Tasks
{
    public class Cleaning
    {

        private TextBox LOG { get; set; }

        public Cleaning(TextBox log)
        {
            this.LOG = log; 
        } 

        public void cleanRoom()
        {
            LOG.Text += "Dusting...."; 
            Thread.Sleep(50000); //work sim
            LOG.Text += "Sweeping...."; 
            Thread.Sleep(50000); //work sim
            LOG.Text += "Hanging up clothes...."; 
            Thread.Sleep(50000); //work sim
            LOG.Text += "Organize shelves...."; 
            Thread.Sleep(50000); //work sim
            LOG.Text += "Remaining odds and ends...."; 
            Thread.Sleep(50000); //work sim
        }
    }
}

尝试3:我尝试在清理中使用Dispatcher并遇到编译错误,告诉我它不存在。所以现在我被卡住了。我不知道还有什么可以尝试的。我搜索了一堆,但它始终归结为线程所有权错误。

if (Dispatcher.Thread != Thread.CurrentThread)
{
    Dispatcher.Invoke(new Action(delegate { this.LOG.Text += "No clean for you!"; }));
}
else
{
    this.LOG.Text += "No clean for you!";
}

所有人的TextBox:

<TextBox Name="tbLog"
    Height="200" 
    Width="200"
    HorizontalAlignment="Left" 
    VerticalAlignment="Top"  
    VerticalScrollBarVisibility="Visible" 
    IsReadOnly="True" />  

感谢您的帮助!

4 个答案:

答案 0 :(得分:4)

我昨天只是在试图从另一个线程逐步加载ListBox。我通过将Dispatcher.Invoke()更改为Application.Current.Dispatcher.Invoke()来实现它。

答案 1 :(得分:0)

这是因为您不能仅对主UI线程以外的其他线程执行控件操作。如果您想这样做,则必须使用Invoke中的BeginInvokeDispatcher

可以找到here的简介,您还可以找到有助于解决此问题的代码示例。

答案 2 :(得分:0)

我想说最好的方法是将文本框的text属性绑定到依赖项属性,并从backgroundworker更新依赖项属性。要从线程更新文本框的值,您需要实现INotifyPropertyChanged。

答案 3 :(得分:0)