Wpf 在另一个线程中使用BitmapDecoder,然后在何处创建。(调用线程无法访问此对象,因为其他线程拥有它。)

Wpf 在另一个线程中使用BitmapDecoder,然后在何处创建。(调用线程无法访问此对象,因为其他线程拥有它。),wpf,multithreading,bitmap,Wpf,Multithreading,Bitmap,因此,我有一个函数,可以从另一个线程的磁盘异步加载一个映像(将加载大映像,我不希望在加载时锁定UI线程) 加载是这样完成的 public override void LoadFile() { using (var imageStream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) { De

因此,我有一个函数,可以从另一个线程的磁盘异步加载一个映像(将加载大映像,我不希望在加载时锁定UI线程)

加载是这样完成的

  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();
            }
        }
然后我想在主线程上使用解码器

   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;
        }
在获得IImageFile后,我们调用MainThread(UIThread)

其中LoadPages是应用程序中断的位置。也在UIThread上调用 公共列表加载页() { var result=新列表()


我认为您可以简单地从线程返回解码器,以便能够访问它,但您的解码器是从DispatcherObject()继承的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
{
}
公共部分类主窗口:窗口
{
公共主窗口()
{
}
公共TiffBitmapDecoder加载文件()
{
OpenFileDialog OpenFileDialog=新建OpenFileDialog();
openFileDialog.InitialDirectory=“c:\\”;
openFileDialog.Filter=“tiff文件(*.tif)|*.tif |所有文件(*.*)|*.”;
openFileDialog.FilterIndex=2;
openFileDialog.RestoreDirectory=true;
if(openFileDialog.ShowDialog()==true&&!string.IsNullOrEmpty(openFileDialog.FileName))
{
//我没有检查文件扩展名,因为它只是一个示例
使用(var imageStream=openFileDialog.OpenFile())
{
返回新的TiffBitmapDecoder(imageStream、BitmapCreateOptions.PreservePixelFormat、BitmapCacheOption.OnLoad);
}
}
其他的
{
//用户取消
返回null;
}
}
公共列表加载页(TiffBitmapDecoder)
{
//TiffBitmapDecoder“继承自DispatcherObject/>
//https://docs.microsoft.com/en-gb/dotnet/api/system.windows.threading.dispatcherobject?view=netcore-3.1
var result=新列表();
if(解码器!=null)
{
尝试
{
foreach(解码器中的var帧。帧)
{
结果。添加(新的缩略图模型)
{
//设置变量
});
}
}
捕获(无效操作异常)
{
MessageBox.Show(例如,Message,“Error”);
}
}
其他的
{
//无事可做
}
返回结果;
}
专用异步任务异步加载()
{
this.thumbnailModels=等待任务。运行(()=>
{
var decoder=this.LoadFile();
返回此.LoadPages(解码器);
});
}
私有列表thumbnailModels=null;
私有异步void AsyncLoadingButton_单击(对象发送方,RoutedEventTarget e)
{
等待此消息。AsyncLoading();
}
}
公共类缩略图模型
{
}
MainWindow.xaml的内容以防万一:

<Grid>
    <StackPanel Orientation="Vertical">
        <Button x:Name="NoReturnButton" Margin="10" HorizontalAlignment="Center" Content="Call AsyncLoadingNoReturn" Click="AsyncLoadingButton_Click" />
    </StackPanel>
</Grid>


如果您进行“加载”"线程返回解码器,您应该能够在主线程中访问。在没有看到所有代码的情况下,我无法真正给出示例。@Ostas我将在一秒钟内更新代码。下周我将对其进行测试,并给出一个答案,如果它对我的情况有帮助,无论如何,非常感谢您的努力。这不会解决我的问题,因为我必须返回一个接口from加载文件(),但您的答案回答了我的问题。我无法在其他线程中使用解码器,因此我将其标记为答案。谢谢
        foreach (var frame in Decoder.Frames)
        {
            result.Add(new ThumbnailModel
            {
                Name = _metadataLoader.GetPageName((BitmapMetadata)frame.Metadata),
                Bitmap = new WriteableBitmap(frame)
            });
        }

        return result;
    }
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
{
}
<Grid>
    <StackPanel Orientation="Vertical">
        <Button x:Name="NoReturnButton" Margin="10" HorizontalAlignment="Center" Content="Call AsyncLoadingNoReturn" Click="AsyncLoadingButton_Click" />
    </StackPanel>
</Grid>