开发者

C# WPF / XAML access TextBox from anywhere/any thread help

I'm trying to post to a text box from anywhere in my program, regardless of what thread it's in or what object owns it etc...

I've tried a few things below, all won't work.

Attempt 1: tbLog doesn't exist in Cleaning and another thread owns it.

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
        开发者_JAVA技巧    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
        }
    }
}

Attempt 2: I tried to pass tbLog into Cleaning. I got this error "The calling thread cannot access this object because a different thread owns it". Which makes sense.

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
        }
    }
}

Attempt 3: I tried to use Dispatcher in Cleaning and got compile error telling me it doesn't exist. So now I'm stuck. I don't know what else to try. I googled a bunch, but it always comes down to the thread ownership error.

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!";
}

The TextBox for all:

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

Thanks for any help!


I was just messing with this yesterday trying to incrementally load a ListBox from another thread. I got it to work by changing Dispatcher.Invoke() to Application.Current.Dispatcher.Invoke().


This is because you can't just perform actions on controls from other threads than the main UI thread. If you want to do this, you have to use Invoke or BeginInvoke from the Dispatcher.

A introduction to this can be found here, you will also find code examples there which will help you with this problem.


I'd say the best way would be to bind the text property of your textbox to a dependency property, and update the dependency property from your backgroundworker. For the text box's value to update from the thread, you'll need to implement INotifyPropertyChanged.


You need to Build More Responsive Apps With The Dispatcher.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜