Exibir imagem da matriz de bytes em WPF - problemas de memória
-
27-09-2019 - |
Pergunta
Desenvolvi um aplicativo para capturar e salvar imagens em um banco de dados, mas estou tendo um problema com o uso da memória. No meu objeto de domínio, tenho 3 propriedades:
Imagem - Array de bytes, o conteúdo é um JPG
RealImagethumb - A matriz de bytes convertida em um bitmapimage e encolheu, exibida ao usuário em uma Gridview com outras miniaturas
Realimage - não possui Setter, a matriz de bytes convertida em uma fonte de bitmap, isso é mostrado em uma dica de ferramenta quando o usuário paira sobre ela.
O problema que tenho é que, se um usuário pairar sobre cada imagem, por sua vez, o uso da memória espiral. Sei que, à medida que um usuário paira sobre fontes de bitmap é gerado e a memória não é liberada, tentei dar à Realimage uma propriedade de apoio e atribuí -lo a nulo depois, mas novamente a memória não é liberada (esperando o lixo colecionador?).
editar:
É isso que você quis dizer Ray? Não estou recebendo nada mostrado na dica de ferramenta como abaixo, mas se eu tentar definir um WeakReference<BitmapImage>
, Eu recebo o sistema.WeakReference não possui erro de parâmetros de tipo.
private WeakReference _realImage;
public virtual BitmapImage RealImage
{
get
{
if (_realImage == null || _realImage.Target == null)
{
if (Image == null) return null;
var newBitmapImage = new BitmapImage();
newBitmapImage.BeginInit();
newBitmapImage.CacheOption = BitmapCacheOption.None;
newBitmapImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
newBitmapImage.StreamSource = new MemoryStream(Image);
newBitmapImage.EndInit();
_realImage = new WeakReference(newBitmapImage);
}
return (BitmapImage)_realImage.Target;
}
}
Solução
Você precisará fazer três coisas:
Ao construir seu bitmapimage, use o STreamSource para fornecer os dados. Não use o Urisource ou passe um URI para o construtor, o que faria com que a imagem fosse adicionada ao cache da imagem.
Na implementação do Realimage do seu objeto de domínio, armazene uma referência fraca para o seu bitmapimage, e não o próprio bitmapimage. Quando o RealImage for buscado, se a referência fraca ou a referência fraca. O alvo for nulo, crie um novo bitmapimage e uma nova referência fraca.
Use um datatrigger com troca de modelo para incluir apenas seu controle de imagem na árvore visual quando estiver visível
Aqui estão os modelos necessários para a Etapa 3, incluindo o do Datatrigger:
<DataTemplate x:Key="EmptyTemplate">
</DataTemplate>
<DataTemplate x:Key="RealImageTemplate">
<Image Source="{Binding RealImage.Target}" Width="300" Height="300" />
</DataTemplate>
<DataTemplate x:Key="RealImageWhenVisible">
<!-- Use EmptyTemplate when I am not visible -->
<ContentPresenter x:Name="Presenter"
Content="{Binding}"
ContentTemplate="{StaticResource EmptyTemplate}"/>
<!-- Switch to RealImageTemplate when I am visible -->
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsVisible, RelativeSource={RelativeSource Self}}"
Value="True">
<Setter TargetName="Presenter"
Property="ContentPresenter.ContentTemplate"
Value="{StaticResource RealImageTemplate}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Agora você pode definir sua dica de ferramenta assim:
<Rectangle Width="40" Height="40" Fill="Blue">
<Rectangle.ToolTip>
<ContentPresenter Content="{Binding}"
ContentTemplate="{StaticResource RealImageWhenVisible}" />
</Rectangle.ToolTip>
</Rectangle>
Como funciona: existem dois conteúdo de propresentadores dentro um do outro:
- Quando o excesso de conteúdo externo é invisível, o conteúdo interno do PRESENTRENTER terá o vazio, para que nenhuma imagem seja carregada.
- Quando o excesso de conteúdo externo estiver visível, o interior do conteúdo do RealImageTemplate para que a imagem seja carregada e exibida.
O motivo pelo qual você precisa fazer isso é que uma dica de ferramenta pode tentar otimizar o desempenho por não descartar o pop -up depois de ser mostrado.
Atualizar
O código que você postou para o Realimage deve trabalhar e é quase exatamente o que eu estava pensando. Percebi que esta manhã não há realmente necessidade de definir o BitmapCacheOption ou o BitmapCreateOption, desde que nenhum fonte seja especificado. Atualizei minha resposta para refletir isso e também para esclarecer a coisa da referência fraca. Também corrigi um bug no modelo: eu estava vinculando ao "Realimage" quando deveria estar vinculado ao "realimage.Target".