【问题标题】:Invoking a control from backgroundworker stops with no error从后台工作人员调用控件停止且没有错误
【发布时间】:2015-12-08 08:20:35
【问题描述】:

我正在运行一个BackgroundWorker,它应该会更新我的UserControl。我在检查InvokeRequired 属性后尝试调用:

private void bgwHighlightText_DoWork(object sender, DoWorkEventArgs e)
{
   tmpRich.SelectedRtf = myRtf;
   if (_ucResultRich.InvokeRequired && _ucResultRich.rchResult.InvokeRequired)
     _ucResultRich.Invoke(new Action(() => _ucResultRich.rchResult.Rtf = tmpRich.Rtf)); // Debug pointer stops here

   //Rest of the code
}

我还尝试直接在我的UserControl 中调用RichTextBox

_ucResultRich.rchResult.Invoke(new Action(() => _ucResultRich.rchResult.Rtf = tmpRich.Rtf));

但是当我调试代码时,它只是停止运行其余代码而没有错误。

_ucResultRich.InvokeRequired_ucResultRich.rchResult.InvokeRequired 都返回 true

我在这里做错了吗?

更新

我将Invoke 部分放在try catch 中,现在我可以从异常消息中得到以下错误:

Cross-thread operation not valid: Control '' accessed from a thread 
      other than the thread it was created on.

是因为它无法确定控件吗?因为它显示为Control ''

【问题讨论】:

  • backgroundworker 的重点在于轻松创建 2 个线程:一个用于 GUI,另一个用于其他东西。它包括在两个线程之间完美通信所需的所有内容,但您必须正确使用它。 DoWork 事件启动后台工作线程,因此,您无法从那里修改属于 GUI 线程的内容(例如,任何控件)。要在控件中执行任何修改,您应该等待后台工作线程完成(通过RunWorkerCompleted 事件)或调用WorkerReportsProgress(+ 知道如何使用它)...
  • ... 总之:您应该学会正确使用 backgroundworker 或根本不使用它(还有其他多线程方法)。您正在尝试的 (Invoke) 没有任何意义:您正在混合使用不同的方法(并没有最大化使用后台工作程序的主要原因,其内置功能的简单性)通常会导致错误永远不会发生(= 未正确使用给定变量的结果)。
  • 你是在为做错事辩护吗?!如前所述:您错误地使用了后台工作程序;并且您尝试解决错误(+建议的解决方案)并没有太大意义。 backgroundworker 具有内置事件以允许两个线程之间的通信,您应该正确使用它们(= 了解 DoWork 的含义/暗示)。如果您不使用 backgroundworker 的内置功能,那么使用它有什么意义呢?!这是一种非常有限的多线程方法(= 只有 2 个线程)。
  • 你在说什么!???如果你不知道什么,你为什么不直接问而不是说没有任何意义的事情?! backgroundworker 的重点在于避免 GUI 冻结。这些事件允许 GUI 和后台工作线程之间进行适当的通信。在其他多线程方法中,您必须自己创建所有这些; backgroundwer 内置了所有内容,可以立即使用。
  • 说真的?!所以你发现了backgroundworker的多线程方式的一个bug?它不适用于图片框?你不觉得也许你用错了吗?此外,如果您认为,解决方案将很简单:不要使用后台工作程序;使用不同的多线程方法。无论如何……随心所欲。我已经写了足够清晰的 cmets 供未来的读者正确理解这种情况。

标签: c# winforms backgroundworker invoke invokerequired


【解决方案1】:

在使用其他线程更新 UI 线程上的控件时,您需要调用委托而不是操作。

您可以使用我的通用方法来实现:

public delegate void SetControlPropertyDelegateHandler(Control control, string propertyName, object value);

public static void SetControlProperty(Control control, string propertyName, object value)
{
 if (control == null) 
     return;
 if (control.InvokeRequired)
 {
    SetControlPropertyDelegateHandler dlg = new SetControlPropertyDelegateHandler(SetControlProperty);
    control.Invoke(dlg, control, propertyName, value);
 }
 else
 {
    PropertyInfo property = control.GetType().GetProperty(propertyName);
    if (property != null)
        property.SetValue(control, value, null);
 }
}

你可以像这样使用这个方法:

SetControlProperty(_ucResultRich.rchResult, "Rtf", tmpRich.Rtf); 

更新

您可以使用此方法在控件上调用无参数方法:

public static void CallMethodUsingInvoke(Control control, Action methodOnControl)
    {
        if (control == null)
            return;
        var dlg = new MethodInvoker(methodOnControl);
        control.Invoke(dlg, control, methodOnControl);
    }

例子:

CallMethodUsingInvoke(richTextBox1, () => _ucResultRich.rchResult.SelectAll());

要调用更复杂的方法,您必须为需要调用的方法创建适当的委托。

更新 2

要从其他线程的属性中获取值,您可以使用此方法:

public delegate object GetControlPropertyValueDelegate(Control controlToModify, string propertyName);

public static T GetControlPropertyValue<T>(Control controlToModify, string propertyName)
{
    if (controlToModify.InvokeRequired)
    {
        var dlg = new GetControlPropertyValueDelegate(GetControlPropertyValue);
        return (T)controlToModify.Invoke(dlg, controlToModify, propertyName);
    }
    else
    {
        var prop = controlToModify.GetType().GetProperty(propertyName);
        if (prop != null)
        {
            return (T)Convert.ChangeType(prop.GetValue(controlToModify, null), typeof(T));
        }
    }
    return default (T);
 }

例子:

var textLength = GetControlPropertyValue<int>(_ucResultRich.rchResult, "Length");

【讨论】:

  • 附注:我建议您另外编写一个 PropertyNameResolver (Expression to String) 来摆脱硬编码的属性字符串参数
  • 这是一个很酷的解决方案。但是你也可以用这个来打电话给_ucResultRich.rchResult.SelectAll()吗?
  • @AlexJolig 您是否认真地通过使用违背其目的的东西来发现问题(甚至不了解它是如何工作的)?!这很奇怪吗?
  • @varocarbas 因为我真的不知道我还能如何解决我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-23
  • 2015-05-27
  • 1970-01-01
相关资源
最近更新 更多