在单独的线程上创建并冻结的 BitmapImage 不显示
BitmapImage created on separate thread and frozen does not show
我有一个 Image
,Source
绑定到视图模型 BitmapImage
属性。它是为树视图中的每个树视图项目显示的图标。我想在单独的线程中加载图像,以减少 UI 线程在树初始化期间的阻塞。
我已经阅读了类似问题的各种答案,但我还没有找到解决这个特定问题的方法。我知道要使 BitmapImage
跨线程可用,您必须 Freeze
图像,但正是这种冻结停止了渲染。
我加载图片如下:
private void LoadImage()
{
Task.Run(() =>
{
if (string.IsNullOrWhiteSpace(_imagePath))
return ;
string[] resources = GetResourceNames();
var result = resources?.FirstOrDefault(x => String.Equals(x, _image, StringComparison.CurrentCultureIgnoreCase)) ??
resources?.FirstOrDefault(x => String.Equals(Path.GetFileName(x), _imagePath, StringComparison.CurrentCultureIgnoreCase));
var image = result == null ? null : new BitmapImage(GetUri(ImageResourceCache.ImagesAssembly.FullName, result));
if (image == null) return;
image.CacheOption = BitmapCacheOption.OnLoad; //<== a suggested solution that does not make a difference
image.Freeze();//<== freezing stops the cross thread exception but stops rendering
DispatcherHelp.CheckInvokeOnUI(() => Image = image);
});
}
private static string[] GetResourceNames()
{
var asm = ImageResourceCache.ImagesAssembly;
var resName = asm.GetName().Name + ".g.resources";
using (var stream = asm.GetManifestResourceStream(resName))
{
if (stream == null) return null;
using (var reader = new ResourceReader(stream))
return reader.Cast<DictionaryEntry>().Select(entry => (string)entry.Key).ToArray();
}
}
private static Uri GetUri(string dllName, string relativeFilePath)
{
return new Uri($"/{dllName};component/{relativeFilePath}", UriKind.RelativeOrAbsolute);
}
LoadImage
在视图模型构造函数中被调用。 _imagePath 被传递给构造函数。
如果我删除 Task.Run 和它呈现的冻结。放回冻结,它不再呈现。
绑定如下:
<Image Source="{Binding Image}" Stretch="Uniform" Margin="0 0 3 0" />
视图模型:
public BitmapImage Image
{
get => _image;
set
{
_image = value;
RaisePropertyChanged();
}
}
您应该使用 pack URI 来识别图像资源。如果有 image/pic.jpeg 资源,这应该可以工作:
Task.Run(() =>
{
BitmapImage image = new BitmapImage(new Uri("pack://application:,,,/images/pic.jpeg", UriKind.RelativeOrAbsolute));
image.Freeze();
Dispatcher.BeginInvoke(new Action(() => Image = image));
});
您的 GetUri
方法似乎缺少 pack://application:,,,/
部分。当您可以使用包 URI 时,就没有理由像您当前正在做的那样查找资源。
我有一个 Image
,Source
绑定到视图模型 BitmapImage
属性。它是为树视图中的每个树视图项目显示的图标。我想在单独的线程中加载图像,以减少 UI 线程在树初始化期间的阻塞。
我已经阅读了类似问题的各种答案,但我还没有找到解决这个特定问题的方法。我知道要使 BitmapImage
跨线程可用,您必须 Freeze
图像,但正是这种冻结停止了渲染。
我加载图片如下:
private void LoadImage()
{
Task.Run(() =>
{
if (string.IsNullOrWhiteSpace(_imagePath))
return ;
string[] resources = GetResourceNames();
var result = resources?.FirstOrDefault(x => String.Equals(x, _image, StringComparison.CurrentCultureIgnoreCase)) ??
resources?.FirstOrDefault(x => String.Equals(Path.GetFileName(x), _imagePath, StringComparison.CurrentCultureIgnoreCase));
var image = result == null ? null : new BitmapImage(GetUri(ImageResourceCache.ImagesAssembly.FullName, result));
if (image == null) return;
image.CacheOption = BitmapCacheOption.OnLoad; //<== a suggested solution that does not make a difference
image.Freeze();//<== freezing stops the cross thread exception but stops rendering
DispatcherHelp.CheckInvokeOnUI(() => Image = image);
});
}
private static string[] GetResourceNames()
{
var asm = ImageResourceCache.ImagesAssembly;
var resName = asm.GetName().Name + ".g.resources";
using (var stream = asm.GetManifestResourceStream(resName))
{
if (stream == null) return null;
using (var reader = new ResourceReader(stream))
return reader.Cast<DictionaryEntry>().Select(entry => (string)entry.Key).ToArray();
}
}
private static Uri GetUri(string dllName, string relativeFilePath)
{
return new Uri($"/{dllName};component/{relativeFilePath}", UriKind.RelativeOrAbsolute);
}
LoadImage
在视图模型构造函数中被调用。 _imagePath 被传递给构造函数。
如果我删除 Task.Run 和它呈现的冻结。放回冻结,它不再呈现。
绑定如下:
<Image Source="{Binding Image}" Stretch="Uniform" Margin="0 0 3 0" />
视图模型:
public BitmapImage Image
{
get => _image;
set
{
_image = value;
RaisePropertyChanged();
}
}
您应该使用 pack URI 来识别图像资源。如果有 image/pic.jpeg 资源,这应该可以工作:
Task.Run(() =>
{
BitmapImage image = new BitmapImage(new Uri("pack://application:,,,/images/pic.jpeg", UriKind.RelativeOrAbsolute));
image.Freeze();
Dispatcher.BeginInvoke(new Action(() => Image = image));
});
您的 GetUri
方法似乎缺少 pack://application:,,,/
部分。当您可以使用包 URI 时,就没有理由像您当前正在做的那样查找资源。