调用线程无法访问此对象,因为在通过类的析构函数从画布中删除 Label 时,其他线程拥有它

本文关键字:线程 布中 删除 析构函数 Label 拥有 其他 访问 对象 因为 调用 | 更新日期: 2023-09-27 17:56:23

我有一个对象 IntervalLabel,当这个对象被删除时,当调用析构函数时,我无法从画布中删除标签,

这段代码对我来说很有意义,但它会导致错误

commonParameters.mainCanvas.Children.Remove(intervalLabel);

错误是:

An unhandled exception of type 'System.InvalidOperationException' occurred 
in WindowsBase.dll 

附加信息:

The calling thread cannot access this object because a different thread owns it.

此外,这行代码不会导致错误,

intervalLabel.MouseLeftButtonDown -= new
System.Windows.Input.MouseButtonEventHandler(IntervalLabel_MouseDown);

如何通过析构函数从画布中删除标签?

class IntervalLabel
{
    private Label intervalLabel;
    public IntervalLabel(Canvas mainCanvas)
    {
        intervalLabel = new Label();
        mainCanvas.Children.Add(intervalLabel);
        intervalLabel.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(IntervalLabel_MouseDown);
    }
    private void IntervalLabel_MouseDown(object sender, MouseEventArgs e)
    {
        //....
    }
    ~IntervalLabel()
    {
        intervalLabel.MouseLeftButtonDown -= new         System.Windows.Input.MouseButtonEventHandler(IntervalLabel_MouseDown);
        commonParameters.mainCanvas.Children.Remove(intervalLabel);
    }
}

调用线程无法访问此对象,因为在通过类的析构函数从画布中删除 Label 时,其他线程拥有它

终结

器(为您运行~ClassName()函数的东西)在它自己的线程上运行,这就是您收到错误的原因,但是您无法执行正常的封送处理,因为当 finializer 调用您的函数时,窗口的上下文可能已经被销毁了。

你不应该把这样的操作放在终结器中,这些操作应该放在类的Dispose函数中。

//Marking the class sealed so we don't need to deal with 
//    the "protected virtual void Dispose(bool disposing)" pattern.
sealed class IntervalLabel : IDisposable
{
    private Label intervalLabel;
    public IntervalLabel(Canvas mainCanvas)
    {
        intervalLabel = new Label();
        mainCanvas.Children.Add(intervalLabel);
        intervalLabel.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(IntervalLabel_MouseDown);
    }
    private void IntervalLabel_MouseDown(object sender, MouseEventArgs e)
    {
        //....
    }
    public void Dispose()
    {
        intervalLabel.MouseLeftButtonDown -= new         System.Windows.Input.MouseButtonEventHandler(IntervalLabel_MouseDown);
        commonParameters.mainCanvas.Children.Remove(intervalLabel);
    }
}

然后,您需要确保在您使用的任何容器中处理完对象后将其处理掉。

话虽如此,你的设计看起来真的很奇怪。我希望从中衍生出一种叫做IntervalLabel的东西,Label里面不包含标签。此外,如果您所做的只是处理鼠标按下事件,则看起来这根本不需要一个类,并且可以在 XAML 或窗体的代码隐藏中处理。