gpt4 book ai didi

c# - WPF 图像控件不处理源

转载 作者:太空狗 更新时间:2023-10-30 01:13:37 26 4
gpt4 key购买 nike

我已经阅读了多个关于此的主题,但仍然找不到任何有用的东西。

我正在编写用于基本浏览图像数据库的程序。我有一个带有 DataTemplate 的 ListView:

<DataTemplate>
<Grid Width="Auto" Height="Auto" >
<Image VerticalAlignment="Center" Source="{Binding IsAsync=True,
Converter={StaticResource Converter},
ConverterParameter={x:Static viewModel:SearchViewModel.MiniaturesHeight}}"
Grid.RowSpan="2" Stretch="None" Margin="5"
Height="{Binding Source={StaticResource Locator}, Path=MiniaturesHeight}"
Width="{Binding Source={StaticResource Locator}, Path=MiniaturesHeight}"
RenderOptions.BitmapScalingMode="NearestNeighbor" />
<TextBlock Text="{Binding Name}" Margin="5" />
</Grid>
</DataTemplate>

在转换器中,我收到对象并根据其内容制作 URL。我的问题是我需要每页显示 100 张图片,例如整个数据库有 40k 张图片。我想允许用户在没有 StackOveflowException 的情况下单击所有页面。不幸的是,每次我更改页面时,内存使用量都会增加并且不会下降,即使我等待很长时间也是如此。

程序本身使用大约 60mb 的 RAM,但在更改页面 5 次后它是 150MB 并且稳步上升。

这是我的第一个转换器:

  public class ObjectToUrl : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return DependencyProperty.UnsetValue;

var obj = value as MyObject;

return "base url" + obj.prop1;


}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}

然后我发现,默认情况下,WPF 使用 InternetExplorer 缓存选项缓存所有传递给 Image 控件的图像。这对我来说是个问题,因为我想要一种简单的方法来在其他用户更改某些内容时更新屏幕上的图像。所以我更改了我的转换器以使用最标准的技术来禁用缓存:

  public class ObjectToUrl : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return DependencyProperty.UnsetValue;

var obj = value as MyObject;

var url = "base url" + obj.prop1;

try
{
var bmp = new BitmapImage();


bmp.BeginInit();
bmp.CacheOption = BitmapCacheOption.None;
bmp.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
bmp.UriSource = new Uri(url);
bmp.EndInit();
return bmp;
}
catch
{
return DependencyProperty.UnsetValue;
}

}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}

这以完全相同的方式工作,除了异常(exception),如果我删除项目并将其添加到绑定(bind)到 ListView 的列表中,它会加载刷新的图像。

我仍然有内存泄漏的问题。有什么想法吗?

最佳答案

增加内存并不总是表示内存泄漏。由于 .NET 是垃圾收集环境 - GC 根据自己的启发式算法自行决定何时运行。该试探法的一部分可能是您的应用程序消耗的内存总量和可用内存总量。假设您有 8GB 可用内存,而您的应用程序消耗了 150MB。 GC 可能会想——何必呢?毕竟,内存是用来使用的,而不是一直空闲的。

因此,为了确保您有内存泄漏 - 您可以尝试定期调用 GC.Collect 并查看这是否有助于回收内存。如果是 - 那么您就没有泄漏。如果不是 - 那么您需要运行探查器并更详细地了解发生了什么。无论如何 - 在您确定没有内存泄漏后,不要将 GC.Collect 留在您的代码中。在非常罕见和特定的情况下,可能值得保留它,但总的来说 - 让 GC 完成它的工作并在它认为合适时回收内存。它很可能比您更清楚何时该做这件事。

不过,BitmapImage 的情况有点复杂。它是非托管资源的包装器,所有此类包装器都应提供 Dispose 方法,以便调用者可以立即回收它使用的非托管内存(因为,与托管内存不同 - 非托管通常可以 立即回收,没有垃圾收集器管理它)。

无论出于何种历史原因,BitmapImage (BitmapSource) 都没有提供这样的方法(至少不是公开的,可能您可以通过反射访问它)。但是,非托管资源指针被包装到具有终结器的 SafeHandle 中。除此之外 - BitmapSource 调用 GC.AddMemoryPressure(至少在现代 .NET 版本中)以通知垃圾收集器它持有 X 字节的非托管内存。

这意味着 GC 确切地知道 BitmapImage 消耗了多少内存,即使大部分内存是非托管的,并且可以在决定何时运行垃圾回收时考虑到这一点。收集 BitmapImage 时 - 它是 SafeHandle 终结器运行并回收非托管内存。

长话短说:在您的情况下什么都不做应该没问题。

关于c# - WPF 图像控件不处理源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49072438/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com