在调用InitializeComponent和使用invoke/lock时出现“对象正在其他地方使用”的错误

3

我有一个应用程序,其中有一个文本框,我需要从多个线程更新该文本框。由于我从多个线程更新文本框,因此我使用以下代码来确保在必要时从主线程调用它 - 但即使有了这个代码,我仍然会出现错误 - 具体来说是“对象当前正在其他地方使用”。

我使用的代码:

private static readonly object setTextLockObject = new object();
delegate void SetTextCallBack(XtraForm Form, string ControlToUpdate, string ControlValue);

public void UpdateControlText(XtraForm Form, string ControlToUpdate, string ControlValue)
{
    try
    {
        if (Form.Controls[ControlToUpdate].InvokeRequired)
        {
            SetTextCallBack callBackHandler = UpdateControlText;
            IAsyncResult invokeResult = Form.Controls[ControlToUpdate].BeginInvoke(callBackHandler, Form, ControlToUpdate, ControlValue);
            Form.Controls[ControlToUpdate].EndInvoke(invokeResult);
        }
        else
        {
            try
            {
                lock (setTextLockObject)
                {
                    Form.Controls[ControlToUpdate].Text = ControlValue.Translate();
                }
            }
            catch (Exception x)
            {
                UpdateStatus(string.Format("ControlText1: {0} ControlToUpdate={1}ControlText={2}", x.Message, ControlToUpdate, ControlValue));
            }
        }
    }
    catch (Exception ex)
    {
         UpdateStatus(string.Format("ControlText2: {0} ControlToUpdate={1} ControlText={2}", ex.Message, ControlToUpdate, ControlValue));
    }
}

我正在使用invoke更新文本,并确保锁定对象,以使另一个线程在更新时无法访问该对象。 我期望第二个线程等待锁被释放,但实际上我收到“对象当前正在使用”的错误提示信息。请问有人可以帮我理解我做错了什么吗?
在表单应用程序中进行应用程序转换时,我遇到了更大的问题-在InitializeComponent中也出现了“对象当前正在别处使用”的错误提示信息。这是一个新对象,没有在任何其他地方使用。为什么在初始化组件时可能会出现此错误?
at System.Drawing.Graphics.get_PageUnit()
at DevExpress.Utils.Text.FontsCache.GetFontCacheByFont(Graphics graphics, Font font)
at DevExpress.Utils.Text.FontsCache.GetStringSize(Graphics graphics, String text, Font font, StringFormat stringFormat, Int32 maxWidth)
at DevExpress.Utils.Text.TextUtils.GetStringSize(Graphics g, String text, Font font, StringFormat stringFormat, Int32 maxWidth)
at DevExpress.Utils.Paint.XPaintMixed.CalcTextSize(Graphics g, String s, Font font, StringFormat strFormat, Int32 maxWidth)
at DevExpress.Utils.AppearanceObject.CalcTextSize(Graphics g, StringFormat sf, String s, Int32 width)
at DevExpress.XtraEditors.ViewInfo.LabelControlViewInfo.CalcSimpleTextSize(String Text, Boolean useHotkeyPrefix, LabelAutoSizeMode mode, Int32 predWidth)
at DevExpress.XtraEditors.ViewInfo.LabelControlViewInfo.CalcTextSize(String Text, Boolean useHotkeyPrefix, LabelAutoSizeMode mode, Int32 predWidth)
at DevExpress.XtraEditors.LabelControl.GetPreferredSize(Size proposedSize)
at DevExpress.XtraEditors.LabelControl.SetBoundsCore(Int32 x, Int32 y, Int32 width, Int32 height, BoundsSpecified specified)
at System.Windows.Forms.Control.System.Windows.Forms.Layout.IArrangedElement.SetBounds(Rectangle bounds, BoundsSpecified specified)
at System.Windows.Forms.Layout.CommonProperties.SetAutoSize(IArrangedElement element, Boolean value)
at System.Windows.Forms.Control.set_AutoSize(Boolean value)
at DevExpress.XtraEditors.LabelControl.set_AutoSizeMode(LabelAutoSizeMode value)
at AccessControl.frmRefillCard.InitializeComponent()

任何帮助都将不胜感激。

顺便说一下,你不需要锁定 - 因为此时发生的一切都在单个UI线程中,所以无法同时访问文本的多个线程。 - Matti Virkkunen
1个回答

0

我认为你在UI线程上让UpdateControlText方法调用自身,这样会使事情变得复杂。而且连续调用BeginInvokeEndInvoke也没有意义。

那么怎么样呢:

public void UpdateControlText(XtraForm Form, string ControlToUpdate, string ControlValue)
{
    if (Form.Controls[ControlToUpdate].InvokeRequired)
    {
        try
        {
            Form.Controls[ControlToUpdate]
                .Invoke(() => Form.Controls[ControlToUpdate].Text = ControlValue.Translate());
        }
        catch (Exception x)
        {
            UpdateStatus(string.Format("ControlText1: {0} ControlToUpdate={1}ControlText={2}", 
                x.Message, ControlToUpdate, ControlValue));
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接