WPFのバイト配列から画像を表示 - メモリの問題
-
27-09-2019 - |
質問
画像をデータベースにキャプチャして保存するアプリケーションを開発しましたが、メモリ使用に関する問題が発生しています。私のドメインオブジェクトには、3つのプロパティがあります。
画像 - バイト配列、コンテンツはJPGです
RealimageThumb -BitMapImageに変換され、縮小されたバイト配列は、他のサムネイルと一緒にグリッドビューでユーザーに表示されます
RELEMAGE -BITMAPソースに変換されたバイト配列、セッターはありません。これは、ユーザーがその上に浮かぶときにツールチップに表示されます。
私が抱えている問題は、ユーザーが各画像の上に順番に順調に進んだ場合、メモリの使用状況がスパイラルスパイラルすることです。ユーザーがビットマップソースを覆い、メモリが解放されていないので、私はバッキングプロパティをRELIMAGEに与えて、これをnullに割り当てようとしましたが、メモリは解放されません(ゴミを待っていませんコレクタ?)。
編集:
これはあなたがレイの意味ですか?以下のようにツールチップに表示されているものは何もありませんが、定義しようとすると WeakReference<BitmapImage>
, 、system.weakreferenceにはタイプパラメーターエラーがありません。
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;
}
}
解決
あなたは3つのことをする必要があります:
BitMapimageを構築するときは、StreamSourceを使用してデータを提供します。 Urisourceを使用したり、URIをコンストラクターに渡さないでください。これにより、画像が画像キャッシュに追加されます。
ドメインオブジェクトのRELEMAGE実装では、BitMapImage自体ではなく、BitMapImageの弱者を保存します。 RELEMAGEが取得されると、WeakReferenceまたはWeakReference.targetがnullの場合、新しいBitmapimageと新しいWeakReferenceを作成します。
テンプレートスイッチングを備えたデータストリガーを使用して、視覚ツリーに表示されているときのみの画像コントロールを含めることができます
ステップ3に必要なテンプレートを含むテンプレートは次のとおりです。
<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>
これで、このようなツールチップを定義できます。
<Rectangle Width="40" Height="40" Fill="Blue">
<Rectangle.ToolTip>
<ContentPresenter Content="{Binding}"
ContentTemplate="{StaticResource RealImageWhenVisible}" />
</Rectangle.ToolTip>
</Rectangle>
それがどのように機能するか:互いに2つのコンテンツプレセンターがあります:
- 外側のContentSpresenterが見えない場合、内側のContentSpresenterにはemptyTemplateがあるため、画像はロードされません。
- 外側のContentSpresenterが表示されると、内側のContentPresenterがRealimageTemplateを持ち、画像がロードされて表示されます。
これを行う必要がある理由は、ツールチップが表示されたらポップアップを処分しないことでパフォーマンスを最適化しようとする可能性があるためです。
アップデート
Realimageのために投稿したコードは機能するはずであり、私が考えていたものです。今朝、Sourceuriが指定されていない限り、BitMapCacheoptionまたはBitMapCreateOptionを設定する必要がないことに気付きました。これを反映するために答えを更新し、また弱いことを明確にしました。また、テンプレートのバグも修正しました。「Realimage.target」に拘束されるべきだったときに、「Relimage」に拘束されていました。