C# WPF / XAML 从任何地方/任何线程访问 TextBox 帮助
我试图从程序中的任何位置发布到文本框,无论它位于哪个线程或哪个对象拥有它等等......
我已经尝试了下面的一些方法,但都不起作用。
尝试 1: tbLog 在 Cleaning 中不存在,并且另一个线程拥有它。
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: 我尝试在 Cleaning 中使用 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 Name="tbLog"
Height="200"
Width="200"
HorizontalAlignment="Left"
VerticalAlignment="Top"
VerticalScrollBarVisibility="Visible"
IsReadOnly="True" />
感谢您的帮助!
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
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!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
昨天我只是在搞乱这个尝试从另一个线程增量加载列表框。我通过将 Dispatcher.Invoke() 更改为 Application.Current.Dispatcher.Invoke() 来使其工作。
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().
这是因为您不能只对主 UI 线程以外的其他线程的控件执行操作。如果您想执行此操作,则必须使用
Dispatcher
中的Invoke
或BeginInvoke
。对此的介绍可以在此处找到,您还可以找到那里的代码示例将帮助您解决这个问题。
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
orBeginInvoke
from theDispatcher
.A introduction to this can be found here, you will also find code examples there which will help you with this problem.
我想说最好的方法是将文本框的文本属性绑定到依赖属性,并从后台工作者更新依赖属性。为了从线程更新文本框的值,您需要实现 INotifyPropertyChanged。
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.