我们已经构建了一个巨大的 winforms 项目,已经进行了多年。
有时,我们的用户会遇到类似 this one 的异常.
这个问题的解决办法好像是:
don't acces UI components from a background thread
.
但是由于我们的项目是一个非常大的项目,有很多不同的线程,我们没有成功找到所有这些。
有没有办法检查(使用某些工具或调试选项)哪些组件是从后台线程调用的?
澄清:
我用一个 Form
创建了一个示例 winforms 项目,其中包含两个 Button
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Text = "Clicked!";
}
private void button2_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
button2.BackColor = Color.Red; //this does not throw an exception
//button2.Text = "Clicked"; //this throws an exception when uncommented
});
}
}
单击按钮时,button2
的背景色设置为红色。这发生在后台线程中(这被认为是不良行为)。但是,它不会(立即)抛出异常。我想要一种将此检测为“不良行为”的方法。最好是通过扫描我的代码,但如果只能通过调试来实现(因此一旦从后台线程访问 UI 组件就暂停)也可以。
最佳答案
我有 2 个建议一起使用,第一个是名为 DebugSingleThread 的 Visual Studio 插件.
您可以卡住所有线程并一次处理一个线程(显然是非主 UI 线程)并查看每个线程对控件的访问。我知道这很乏味,但使用第二种方法还不错。
第二种方法是获取重现问题的步骤。如果您知道重现它的步骤,就会更容易看出是什么原因造成的。为此,我做了这个 User Action Log Github 上的项目。
它会记录用户的每一个 Action ,你可以在这里阅读:User Activity Logging, Telemetry (and Variables in Global Exception Handlers) .
我建议您还记录线程 ID,然后当您能够重现问题时,转到日志末尾并计算出确切的步骤。它并不像看起来那么痛苦,而且非常适合获取应用程序遥测数据。
您可以自定义此项目,例如捕获一个 DataSource_Completed 事件或添加一个虚拟 DataSource 属性来设置真正的 Grids DataSource 属性并引发一个 INotifyPropertyChanged
事件 - 如果它是一个非主要的然后是线程 ID Debugger.Break();
。
我的直觉是你正在后台线程中更改控件(例如网格)的数据源(为了那种非卡住的感觉),这会导致同步问题。这就是发生在其他经历过这种情况的 DevExpress 客户身上的情况。其讨论here在与您引用的线程不同的线程中。
关于c# - 找出从后台线程访问了哪些 winforms 控件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48113854/