从backgroundworker调用一个控件停止没有错误

时间:2015-12-08 08:20:36

标签: c# winforms backgroundworker invoke invokerequired

我正在运行一个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
}

我还尝试直接调用RichTextBox内的UserControl

_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 ''

1 个答案:

答案 0 :(得分:1)

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

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

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");