Invoking a control from backgroundworker stops with no error

匆匆过客 提交于 2019-12-11 23:06:32

问题


I'm running a BackgroundWorker which suppose to update my UserControl. I tried Invoking after checking InvokeRequired property:

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
}

I also tried to invoke the RichTextBox inside my UserControl directly:

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

But when I debug the code, it just stops running the rest of the code with no error.

Both _ucResultRich.InvokeRequired and _ucResultRich.rchResult.InvokeRequired return true.

Am I doing something wrong here?

Update

I put the Invoke part in try catch and now I can get the following error from the exception message:

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

Is it because it cant determine the control? Cause it shows it like Control ''.


回答1:


You need to invoke a delegate not an Action when using other threads to update controls on the UI thread.

You can use my general purpose method to achieve this:

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

And you can use this method like this:

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

Update

You can use this method to call parameterless methods on the control:

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

Example:

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

To call more complex methods you must create an appropriate delegate for the method you need to call.

Update 2

To get values from properties from other threads you can use this method:

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

Example:

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


来源:https://stackoverflow.com/questions/34151045/invoking-a-control-from-backgroundworker-stops-with-no-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!