首页 文章

调用线程无法访问此对象,因为另一个线程拥有它[重复]

提问于
浏览
20

这个问题在这里已有答案:

为什么我不能在以下代码中创建CroppedBitmap?我有一个例外:

调用线程无法访问此对象,因为其他线程拥有它 .

如果我将代码更改为

CroppedBitmap cb = new CroppedBitmap(new WriteableBitmap(bf), new Int32Rect(1, 1, 5, 5));

异常消失了吗?为什么?

代码1, cb.Freeze() 的例外:

public MainWindow()
{
    InitializeComponent();

    ThreadPool.QueueUserWorkItem((o) =>
        {
            //load a large image file
            var bf = BitmapFrame.Create(
                new Uri("D:\\1172735642.jpg"),
                BitmapCreateOptions.None,
                BitmapCacheOption.None);
            bf.Freeze();
            Dispatcher.BeginInvoke(
                new Action(() =>
                    {
                        CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
                        cb.Freeze();
                        //set Image's source to cb....
                    }), 
                    DispatcherPriority.ApplicationIdle);
         }
    );
}

代码2,有效:

ThreadPool.QueueUserWorkItem((o) =>
    {
        var bf = BitmapFrame.Create(
                new Uri("D:\\1172740755.jpg"),
                BitmapCreateOptions.None,
                //BitmapCreateOptions.DelayCreation,
                BitmapCacheOption.None);
        bf.Freeze();
        var wb = new WriteableBitmap(bf);
        wb.Freeze();
        this.Dispatcher.Invoke(
            new Action(() =>
            {
                var r = new Int32Rect(1, 1, 5, 5);
                CroppedBitmap cb = new CroppedBitmap(wb, r);
                cb.Freeze();
                //set Image's source to cb....
                Image.Source = cb;
            }),
            DispatcherPriority.ApplicationIdle);
    }
);

代码3,没有WritableBitmap工作:

ThreadPool.QueueUserWorkItem((o) =>
    {
        var bf = BitmapFrame.Create(
                new Uri("D:\\1172735642.jpg"),
                BitmapCreateOptions.None,
                //BitmapCreateOptions.DelayCreation,
                BitmapCacheOption.None);
        bf.Freeze();
        var bf2 = BitmapFrame.Create(bf);
        bf2.Freeze();

        this.Dispatcher.Invoke(
            new Action(() =>
            {
                var r = new Int32Rect(1, 1, 5, 5);
                BitmapSource cb = new CroppedBitmap(bf2, r);
                cb.Freeze();
                //set Image's source to cb....
                Image.Source = cb;
            }),
            DispatcherPriority.ApplicationIdle);
    }
);

4 回答

  • 7

    您可以在反射器中查看此类 . cb.Freeze()中会出现异常 . 在

    CroppedBitmap cb = new CroppedBitmap(bf, new Int32Rect(1,1,5,5));
    

    case构造函数做了这样的事情:

    this.this.Source = source;
    

    因此,源不是在当前线程中创建的,因此异常将会增加 . 在

    new WriteableBitmap(bf)
    

    case,构造函数与bf对象同步,并在当前线程中创建新源,因此,不会出现异常 . 如果您对In Depth详细信息感兴趣,可以随时使用Reflector反映基础库:)

  • 16

    以下代码可能会帮助您解决从另一个线程更新gui元素的问题:

    模块级别

    delegate void updateCallback(string tekst);
    

    这是更新元素的方法:

    private void UpdateElement(string tekst)
    {
        if (element.Dispatcher.CheckAccess() == false)
        {
            updateCallback uCallBack = new updateCallback(UpdateElement);
            this.Dispatcher.Invoke(uCallBack, tekst);
        }
        else
        { 
    //update your element here
        }
     }
    
  • 3

    使用WPF时请注意,如果在一个线程中创建UI对象,则无法从另一个线程访问它 . 您的UI对象应该(通常)创建UI线程,然后您需要UI线程以后访问它们 . 没有其他线程可以访问在UI线程上创建的对象 .

    如果您需要从另一个线程访问UI对象,则需要UI线程Dispatcher,然后您可以使用它来调用UI线程上的调用 .

    我花了很多时间来解决类似的问题 - 相信我..查看this question - 它给了我很多关于这个主题的有用信息 .

  • 2

    我遇到了同样的问题并通过使用其调度程序(可以通过 Application.Current.Dispatcher 访问)在UI线程中创建 UIElement 来解决问题 .

    之前:

    public static UIElement CreateUIElement()
    {
        UIElement element = new UIElement();
        //Initialized the UIElement here
        return element;
    }
    

    此代码导致XamlParseException,因为它在与UI线程不同的线程中调用 .

    我的工作方案:

    public static UIElement CreateUIElement()
    {
        UIElement element = null;
        Application.Current.Dispatcher.Invoke(
           System.Windows.Threading.DispatcherPriority.Normal, new Action(
              delegate()
              {
                  element = new UIElement();
                  // Initialize your UIElement here
              }));
        return element;
    }
    

    有关调度员的更多信息,请点击此处http://tech.pro/tutorial/800/working-with-the-wpf-dispatcher

    祝好运

相关问题