首页 新闻 会员 周边 捐助

C#跨线程操作控件

0
[已解决问题] 解决于 2020-04-26 14:55

为什么调试状态会报错“从不是创建控件“button”的线程访问它”:

1、为什么“开始执行(不调试)”不会报错,”开始调试“就会报错

2、既然“开始执行(不调试)”不会报错,那么使用这个窗体软件时,是不是可以忽略这个问题?忽略了会给我带来什么坏处?
3、为什么修改button的背景颜色,不会报错,修改其他属性会报错?

😀明笔记的主页 😀明笔记 | 初学一级 | 园豆:13
提问于:2020-04-13 11:55
< >
分享
最佳答案
1
  1. 应该是你有全局捕获异常的地方,不调试的情况下直接被捕获了;再者就是这个异常是非UI线程抛出的,非调试是根本看不到。后者原因比较大。
  2. 当然不能忽略,找到问题所在,修复它。
  3. 最好贴出来你的实际代码。

肯定是非UI线程去操作button导致的了(也许你使用了SynchronizationContext,但是部分逻辑没有覆盖到),解决途径就是把这部分操作委托给UI线程去做。

奖励园豆:5
Timetombs | 老鸟四级 |园豆:3959 | 2020-04-13 17:30

void writelist()
{
new Task((delegate ()
{
for (int i = 0; i < Max_Item_Count; i++)
{
listView1.Invoke((MethodInvoker)delegate ()
{
listView1.Items.Add(new ListViewItem(new string[]
{ n.ToString(), string.Format("This is No.{0} item", n.ToString()) }));
n++;
Application.DoEvents();
});
};
//修改属性不可行,报错
button1.Text = "OK";
//修改背景颜色可行!不报错
button1.BackColor = Color.Red;
})).Start();
}

😀明笔记 | 园豆:13 (初学一级) | 2020-04-14 14:08

@😀明笔记:

你就不能格式化以下,,,不然怎么看。。。

void writelist()
{
    new Task((delegate ()
    {
        for (int i = 0; i < Max_Item_Count; i++)
        {
            listView1.Invoke((MethodInvoker)delegate ()
            {
                listView1.Items.Add(new ListViewItem(new string[]
                {
                    n.ToString(),
                    string.Format("This is No.{0} item", n.ToString())
                }
                ));
                n++;
                Application.DoEvents();
            });
        };
        //修改属性不可行,报错
        button1.Text = "OK";
        //修改背景颜色可行!不报错
        button1.BackColor = Color.Red;
    }
    )).Start();
}
Timetombs | 园豆:3959 (老鸟四级) | 2020-04-14 16:24

@😀明笔记: 着实很奇怪,不过我发现还有有些差异,Text是属于Control的,更改它最终会调用

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool SetWindowText(HandleRef hWnd, string text);

但是BackColor则仅只是基类的一个PropertyStore来存储变更即可。

Timetombs | 园豆:3959 (老鸟四级) | 2020-04-14 16:57
其他回答(4)
1

其他线程访问UI线程创建的控件,这就是线程安全问题。解决的办法就是异步方式和设置CheckForIllegalCrossThreadCalls = false ;

数据酷软件 | 园豆:130 (初学一级) | 2020-04-13 12:20

我会处理这个问题。不过就是不理解。为什么有些报错。有些不报错

支持(0) 反对(0) 😀明笔记 | 园豆:13 (初学一级) | 2020-04-13 14:10
0
button1.Invoke((MethodInvoker)(()=>
{
    //这里写逻辑
}));
拓拓 | 园豆:1055 (小虾三级) | 2020-04-13 13:20

我会处理这个问题。不过就是不理解。为什么有些报错。有些不报错

支持(0) 反对(0) 😀明笔记 | 园豆:13 (初学一级) | 2020-04-13 14:10

@😀明笔记: 1. 为什么“开始执行(不调试)”不会报错,”开始调试“就会报错
调试的时候调试器会查看是当前代码块有没有trycatch,如果没有,就会中断并提示你这里报错了,也就是说,哪怕你在其他地方捕获了这个异常,也会在这里提示。正式运行的时候,应该有捕获全局异常,所以没有报错。

  1. 既然“开始执行(不调试)”不会报错,那么使用这个窗体软件时,是不是可以忽略这个问题?忽略了会给我带来什么坏处?
    不一定,如果这个异常是设计的一部分,可以忽略。
    比如说你的代码是可能在UI线程上修改属性,也可能是在后台线程上修改属性,但是你想忽略后台线程的修改,这样的情况就可以忽略。
    忽略这个问题可能造成的结果是界面显示不正确。

  2. 为什么修改button的背景颜色,不会报错,修改其他属性会报错?
    不知道

支持(0) 反对(0) 拓拓 | 园豆:1055 (小虾三级) | 2020-04-13 16:00
0

改成异步调用就行了,这是winfrom程序常见的一个问题,如果用wpf的双向绑定就不会有这个问题

会长 | 园豆:12463 (专家六级) | 2020-04-13 13:34

我会处理这个问题。不过就是不理解。为什么有些报错。有些不报错

支持(0) 反对(0) 😀明笔记 | 园豆:13 (初学一级) | 2020-04-13 14:10

@😀明笔记: 不可能吧
你贴出demo来看看

支持(0) 反对(0) 会长 | 园豆:12463 (专家六级) | 2020-04-13 17:25

@会长: 例如修改button的背景颜色,就不会报错

支持(0) 反对(0) 😀明笔记 | 园豆:13 (初学一级) | 2020-04-14 14:04

@会长: void writelist()
{
new Task((delegate ()
{
for (int i = 0; i < Max_Item_Count; i++)
{
listView1.Invoke((MethodInvoker)delegate ()
{
listView1.Items.Add(new ListViewItem(new string[]
{ n.ToString(), string.Format("This is No.{0} item", n.ToString()) }));
n++;
Application.DoEvents();
});
};
//修改属性不可行,报错
button1.Text = "OK";
//修改背景颜色可行!不报错
button1.BackColor = Color.Red;
})).Start();
}

支持(0) 反对(0) 😀明笔记 | 园豆:13 (初学一级) | 2020-04-14 14:09

@😀明笔记: 没遇到过,我试试

支持(0) 反对(0) 会长 | 园豆:12463 (专家六级) | 2020-04-14 14:44
1

子线程不能修改 主线程(UI线程)控件 。winfrom 规定 。没有为什么,
在其他语言也是一样, 比如安卓开发也是一样

s_p | 园豆:140 (初学一级) | 2020-04-13 15:34

那为什么修改button背景颜色也可以了?

支持(0) 反对(0) 😀明笔记 | 园豆:13 (初学一级) | 2020-04-14 14:05
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册