在其他线程中使用BitmapDecoder,然后在其中创建。 (由于另一个线程拥有该对象,因此调用线程无法访问该对象。)

问题描述 投票:0回答:1

因此,我有一个将从磁盘异步中的另一个线程中加载图像的函数(将加载大图像,并且我不希望UI THread在加载时被锁定)。

这样加载完成

  public override void LoadFile()
        {
            using (var imageStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                Decoder = new TiffBitmapDecoder(imageStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
                InitializeFile();
            }
        }

然后我要在主线程上使用Decoder

   public List<ThumbnailModel> LoadPages()
        {
            var result = new List<ThumbnailModel>();

            foreach (var frame in Decoder.Frames) <--// this line throws exception
            {
                result.Add(new ThumbnailModel
                {
                    Name = _metadataLoader.GetPageName((BitmapMetadata)frame.Metadata),
                    Bitmap = new WriteableBitmap(frame)
                });
            }

            return result;
        }

现在是问题,每当我到达尝试访问Decoder.Frames的行时,它都会引发异常(调用线程无法访问此对象,因为其他线程拥有它。)

是否有办法在主线程中使用我的解码器,唯一可能的解决方案是在其他线程中加载所有图像信息?

完整代码版本://这是任务,它调用imageFactory LoadFile方法-NewThread

  private async Task OpenFileAsync(string strFilePath)
            {
                var newFile = _imageFileFactory.LoadFile(strFilePath);

            if (newFile != null)
            {
                _imagefile = newFile;
            }
        }
  //image factory load file - NewThread
  public IImageFile LoadFile(string filePath)
        {
            if (string.IsNullOrWhiteSpace(filePath))
            {
                return null;
            }

            var fileExtension = Path.GetExtension(filePath); // .tiff or .jpeg

            var file = new ImageFileTiff(filePath, _metatadaFactory, _metadataVersioner);

            file.LoadFile();


            return file;
        }
// ImageFileTiff LoadFile will create a decoder - NewThread
 public override void LoadFile()
        {
            using (var imageStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                Decoder = new JpegBitmapDecoder(imageStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);

                InitializeFile();
            }
        }

[拥有IImageFile之后,我们调用MainThread(UIThread)

var pages = _imagefile.LoadPages(); 

LoadPages是应用程序中断的位置。也称为UIThread公共列表LoadPages(){var result = new List();

        foreach (var frame in Decoder.Frames)
        {
            result.Add(new ThumbnailModel
            {
                Name = _metadataLoader.GetPageName((BitmapMetadata)frame.Metadata),
                Bitmap = new WriteableBitmap(frame)
            });
        }

        return result;
    }
wpf multithreading bitmap
1个回答
0
投票

我以为您可以简单地从线程返回解码器以能够访问它,但是您的解码器是从DispatcherObject(https://docs.microsoft.com/en-gb/dotnet/api/system.windows.threading.dispatcherobject?view=netcore-3.1)继承的TiffBitmapDecoder。

因此,您将无法从与创建msdn的线程不同的线程访问它:“ 只有在Dispatcher上创建的线程可以直接访问DispatcherObject

您可以做的是在其线程中使用解码器并返回最终结果:

我无法建立您的样本,因为我缺少很多东西来测试它,但是我建立了一个类似的项目来举例说明:

public partial class MainWindow : Window
{
    public MainWindow()
    {

    }

    public TiffBitmapDecoder LoadFile()
    {
        OpenFileDialog openFileDialog = new OpenFileDialog();
        openFileDialog.InitialDirectory = "c:\\";
        openFileDialog.Filter = "tiff files (*.tif)|*.tif|All files (*.*)|*.*";
        openFileDialog.FilterIndex = 2;
        openFileDialog.RestoreDirectory = true;

        if (openFileDialog.ShowDialog() == true && !string.IsNullOrEmpty(openFileDialog.FileName))
        {
            //I didn't bother to check the file extension since it's just an exemple
            using (var imageStream = openFileDialog.OpenFile())
            {
                return new TiffBitmapDecoder(imageStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
            }
        }
        else
        {
            //User cancelled
            return null;
        }
    }

    public List<ThumbnailModel> LoadPages(TiffBitmapDecoder decoder)
    {
        //TiffBitmapDecoder" inherits from DispatcherObject/>
        //https://docs.microsoft.com/en-gb/dotnet/api/system.windows.threading.dispatcherobject?view=netcore-3.1
        var result = new List<ThumbnailModel>();
        if (decoder != null)
        {
            try
            {
                foreach (var frame in decoder.Frames)
                {
                    result.Add(new ThumbnailModel
                    {
                        //set the variables
                    });
                }
            }
            catch(InvalidOperationException e)
            {
                MessageBox.Show(e.Message, "Error");
            }
        }
        else
        {
            //Nothing to do
        }
        return result;
    }

    private async Task AsyncLoading()
    {
        this.thumbnailModels = await Task.Run<List<ThumbnailModel>>(() =>
        {
            var decoder = this.LoadFile();
            return this.LoadPages(decoder);
        });
    }

    private List<ThumbnailModel> thumbnailModels = null;

    private async void AsyncLoadingButton_Click(object sender, RoutedEventArgs e)
    {
        await this.AsyncLoading();
    }
}

public class ThumbnailModel
{
}

MainWindow.xaml的内容,以防万一:

<Grid>
    <StackPanel Orientation="Vertical">
        <Button x:Name="NoReturnButton" Margin="10" HorizontalAlignment="Center" Content="Call AsyncLoadingNoReturn" Click="AsyncLoadingButton_Click" />
    </StackPanel>
</Grid>
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.