1

画像をキャプチャしてデータベースに保存するアプリケーションを開発しましたが、メモリ使用量に問題があります。私のドメイン オブジェクトには、3 つのプロパティがあります。

画像 - バイト配列、内容は jpg

RealImageThumb - BitmapImage に変換されて縮小されたバイト配列で、他のサムネイルと共にグリッドビューでユーザーに表示されます

RealImage - ビットマップ ソースに変換されたバイト配列であり、ユーザーがカーソルを合わせるとツールチップに表示されます。

私が抱えている問題は、ユーザーが各画像にカーソルを合わせると、メモリ使用量がスパイラルになることです。ユーザーが生成されたビットマップ ソースにカーソルを合わせてもメモリが解放されないことに気付きました。RealImage にバッキング プロパティを与え、これを 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;
            }
        }
4

1 に答える 1

3

次の3つのことを行う必要があります。

  1. BitmapImageを作成するときは、StreamSourceを使用してデータを提供します。UriSourceを使用したり、コンストラクターにUriを渡したりしないでください。これにより、画像が画像キャッシュに追加されます。

  2. ドメインオブジェクトのRealImage実装で、BitmapImage自体ではなくBitmapImageへのWeakReferenceを格納します。RealImageがフェッチされたときに、WeakReferenceまたはWeakReference.Targetのいずれかがnullの場合、新しいBitmapImageとそれに新しいWeakReferenceを作成します。

  3. テンプレート切り替えでDataTriggerを使用して、画像コントロールが表示されている場合にのみ画像コントロールをビジュアルツリーに含めます

DataTriggerを含むテンプレートを含め、ステップ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つのContentPresenterが互いに内部にあります。

  • 外側のContentPresenterが非表示の場合、内側のContentPresenterにはEmptyTemplateがあるため、画像は読み込まれません。
  • 外側のContentPresenterが表示されている場合、内側のContentPresenterにはRealImageTemplateがあるため、画像が読み込まれて表示されます。

これを行う必要がある理由は、ツールチップが表示されたポップアップを破棄しないことでパフォーマンスを最適化しようとする可能性があるためです。

アップデート

RealImageに投稿したコードは機能するはずであり、私が考えていたものとほぼ同じです。今朝、SourceUriが指定されていない限り、BitmapCacheOptionまたはBitmapCreateOptionを設定する必要がないことに気付きました。これを反映し、WeakReferenceを明確にするために、回答を更新しました。テンプレートのバグも修正しました。「RealImage.Target」にバインドする必要があるときに「RealImage」にバインドしていました。

于 2010-06-16T02:01:18.853 に答える